java多线程的学习.docx
- 文档编号:3034902
- 上传时间:2022-11-17
- 格式:DOCX
- 页数:28
- 大小:27.83KB
java多线程的学习.docx
《java多线程的学习.docx》由会员分享,可在线阅读,更多相关《java多线程的学习.docx(28页珍藏版)》请在冰豆网上搜索。
java多线程的学习
Java多线程的学习
Java线程
一般我们写的程序是单线程的,其main函数就是启动单线程的入口。
在java中可以实现Runable接口或是继承Thread来实现多线程,要实现多线程,就必须执行线程的star方法,执行start方法后,java会在后台启动一个新的线程并执行run方法,当然你也可以直接执行run方法,但是就不会去启动新的线程了。
下面是一个多线程的例子
publicclassThreadMutile{
/**
*@paramargs
*/
publicstaticvoidmain(String[]args){
ThreadZout=newThreadZou();
t.start();//新启动一个线程
for(inti=0;i<100;i++)
System.out.println("main");
}
}
classThreadZouextendsThread{
@Override
publicvoidrun(){
//TODOAuto-generatedmethodstub
for(inti=0;i<100;i++)
System.out.println("zouxiaohu");
}
}
这里会有两个线程一个是main函数,一个是新建立的线程。
你会发现其每次执行结果会有所不同,这是因为线程并发运行的结果
实现线程有两种方法,上面说的是去继承Thread类,另一个方法是去实现Runable接口,然后将其示例传递给Thread构造器进行实例化一个线程,最后调用start方法来进行新建一个线程。
注意:
无论是哪种进行实现线程,新建线程的方法永远是进行调用start方法。
线程的操作
Sleep方法进行暂停,该方法是Thread类的类方法,用法如下:
publicstaticvoidmain(String[]args){
for(inti=0;i<100;i++)
{
System.out.println("tt");
try{
Thread.sleep(2000);//单位ms
}catch(InterruptedExceptione){
//TODOAuto-generatedcatchblock
}
}
这里是每隔2秒会进行打印,与暂停对应的方法是半路唤醒,即是interrupt方法。
后面会进行介绍;
当多个线程访问一个共享资源时此时需要进行方法的同步即是互斥。
比如银行的取款的逻辑如下:
If存款金额>取款金额
进行取款
可能会发生的情况是,两个线程a,b进行同时的访问,刚好b线程夹在a线程的确定余额和可用取款之间,那么就会发生两个线程都进行了取钱,最后则是余额是负数了。
因此需要进行方法的同步
下面是同步块的方法:
publicclassBank{
privateStringname;
privateintmoney;
publicBank(Stringname,intmoney){
this.money=money;
this.name=name;
}
//进行存款
publicsynchronizedvoiddeposit(intm)
{
money+=m;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
//进行取款
publicsynchronizedbooleanwithdrow(intn)
{
if(money>=n){
money=-n;
returntrue;
}else{
returnfalse;
}
}
publicstaticvoidmain(String[]args){
}
}
注意:
对于同一实例只能有一个线程去访问同步的方法(如果有两个实例那么一个实例如果有线程在执行同步方法,不会影响到另一实例的锁定即是:
只要有实例,就会有一个锁定)也就是说如果有线程在进行去钱调用withdrow方法,那么该线程就会去加锁,其余的线程是无法进行调用其他的同步方法(存钱,取钱)此时只能进行等待获取锁。
如果想进行锁定方法的局部,那么可以利用同步代码块
synchronized(表达式)后面进行讲解。
也可以定义类方法的同步:
Publicstaticsynchronizedvoid***这种同步锁定是针对类对象的实例进行锁定,假如类是SomeTh,则是针对SomeTh.class的实例进行锁定的,而一般的方法同步时针对对象的实例进行锁定(static是锁定了所有类对象的实例,而方法的锁定是针对实例的,不同的实例锁是不同的)
线程的协作
线程之间的协作是通过wait、notify、notifyAll来进行实现的:
调用wait方法是首先是要获取到锁,执行此方法后就是线程进行暂停并释放锁
Synchronizedmethod(){
........
obj.Wait();//开始进行等待,释放所
}
调用notify是会让等待的线程进行唤醒,当执行notifyAll时则是唤醒所有的线程。
同样执行notify时要获取锁的权限,执行后就会去释放锁,唤醒的线程就会进行得到锁。
如果没有锁定的线程去调用notfy或是notifyAll则会抛出异常IllegalMonitorStateException。
对于notify和notifyAll方法的调用:
两者很相似,除非你对程序很清楚,否则你最好还是调用notifyAll,这样会好点,不会出现有些线程挂死。
SingleThreadExcutionPattern
下面的一个例子,一个过门的例子,每次只能有一个人进行过门,且过门的人会留下姓名和出生地址,当过门的人的姓名和地址的第一个字母不相同此时门的状态是不对的。
为此我们设置三个类:
1Gate类,里面有计数器、人的姓名和住址,会进行状态检查及过门方法,如下:
/**
*
*@authorAdministrator
*门,每次只能过一个人,且过人时其出生地和下面的第一个字母要相同
*
*/
publicclassGate{
privateStringname;
privateStringaddress;
privateintcount;
publicvoidpass(Stringname,Stringaddress){
this.name=name;
this.address=address;
count++;
check();
}
@Override
publicStringtoString(){
//TODOAuto-generatedmethodstub
return"NO."+count+"name:
"+name+"address:
"+address;
}
publicvoidcheck()
{
if(name.charAt(0)!
=address.charAt(0)){
System.out.println("**Broken***"+toString());
}
}
}
然后进行定义UseGate的线程,此处会引用Gate,初始化人的姓名和住址,并在线程中调用过门的方法如下:
publicclassUseGateThreadextendsThread{
privatefinalGategate;
privatefinalStringname;
privatefinalStringaddress;
publicUseGateThread(Gategate,Stringname,Stringaddress){
this.gate=gate;
this.name=name;
this.address=address;
}
//这个线程是进行过门
@Override
publicvoidrun(){
System.out.println(name+"begin");
while(true){
gate.pass(name,address);
}
}
}
进行主体类的测试
*/
publicstaticvoidmain(String[]args){
//实例化们
Gategate=newGate();
//启动三个线程
UseGateThreadt=newUseGateThread(gate,"zou","zz");
UseGateThreadt1=newUseGateThread(gate,"xiao","xx");
UseGateThreadt2=newUseGateThread(gate,"hu","h");
t.start();
t1.start();
t2.start();
}
}
结果如下:
**Broken***NO.791803769name:
xiaoaddress:
xx
**Broken***NO.791805028name:
xiaoaddress:
xx
**Broken***NO.791806006name:
xiaoaddress:
xx
**Broken***NO.791806938name:
xiaoaddress:
xx
**Broken***NO.791807793name:
xiaoaddress:
xx
**Broken***NO.791808687name:
xiaoaddress:
xx
**Broken***NO.791809605name:
xiaoaddress:
xx
**Broken***NO.791810570name:
xiaoaddress:
xx
**Broken***NO.791811638name:
xiaoaddress:
xx
**Broken***NO.791812889name:
xiaoaddress:
xx
**Broken***NO.791813880name:
xiaoaddress:
xx
**Broken***NO.791815056name:
xiaoaddress:
xx
**Broken***NO.791817184name:
xiaoaddress:
h
**Broken***NO.791817336name:
xiaoaddress:
xx
你会发现姓名和住址的首字母相同也是broken的,这是因为在执行chek方法时候,其他的线程也正在执行pass方法此时的数据进行了改变,因此会出现上面的情况。
由于多线程是多变的,即使测试出来没有问题也不能保证程序是安全的,这和测试的时间和地点及次数都有关系。
上面我们在测试时使用了while的循环才发现问题的。
由于上面的代码使多个线程进行访问了同一pass方法,导致会发生意外的情况,为了保证线程安全,我们知道其Gate是共享资源类,因此对于pass方法应该进行同步方法块来实现线程的安全
对于单线程的
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 多线程 学习