JAVA 26Java线程(下)

上传人:伴*** 文档编号:243077201 上传时间:2024-09-15 格式:PPT 页数:24 大小:271KB
返回 下载 相关 举报
JAVA 26Java线程(下)_第1页
第1页 / 共24页
JAVA 26Java线程(下)_第2页
第2页 / 共24页
JAVA 26Java线程(下)_第3页
第3页 / 共24页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,Java,线程(下),线程的,join(),方法,多线程编程,多线程共享数据,线程之间的通信,线程的,join,方法,Thread API,包含了等待另一个线程完成的方法:,join(),方法。当调用,Thread.join(),时,调用线程将阻塞,直到被,join,方法加入的目标线程完成为止。,Thread.join(),通常由使用线程的程序调用,以将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。,join,方法例子(示例,12-6,),JoinThread,r = new,JoinThread,();,Thread t = new Thread(r);,t.start();,try,t.join();,catch(InterruptedException,e),多线程,多线程编程,多个线程来自同一个,Runnable,实例,多个线程使用同样的数据和代码,例子:,Thread t1 = new Thread(object1);,Thread t2 = new Thread(object1);,多线程例子(示例,12-7,), ,RunningObject,ro,= new,RunningObject,();,Thread t1 = new Thread(ro,1st);,Thread t2 = new Thread(ro,2nd);,t1.start();,t2.start();, ,多线程共享数据时的问题,经典的银行取款问题,有一个银行账户,还有余额,1100,元,现在,A,通过银行卡从中取,1000,元,而同时另外一个人,B,通过存折也从这个账户中取,1000,元。取钱之前,要首先进行判断:如果账户中的余额大于要取的金额,则可以执行取款操作,否则,将拒绝取款。,我们假定有两个线程来分别从银行卡和存折进行取款操作,当,A,线程执行完判断语句后,获得了当前账户中的余额数(,1000,元),因为余额大于取款金额,所以准备执行取钱操作(从账户中减去,1000,元),但此时它被线程,B,打断,然后,线程,B,根据余额,从中取出,1000,元,然后,将账户里面的余额减去,1000,元,然后,返回执行线程,A,的动作,这个线程将从上次中断的地方开始执行:也就是说,它将不再判断账户中的余额,而是直接将上次中断之前获得的余额减去,1000,。此时,经过两次的取款操作,账户中的余额为,100,元,从账面上来看,银行支出了,1000,元,但实际上,银行支出了,2000,元。,共享数据出错例子,堆栈是这样的数据结构:它是一个用于存放数据的队列,最先进入的元素最后一个被释放(后进先出)。用,push(),方法可以把一个元素添加到堆栈顶(称为,压栈,),用不指定索引的,pop(),方法可以把一个元素从堆栈顶释放出来(称为,出栈,或,弹栈,),出栈,压栈,共享数据出错例子(,con.,),以,一个数组来模拟堆栈(,Stack,),的操作:一个方法向堆栈里压(,push in,),数据,一个方法向外弹出(,pop out,),数据,下面是一个用,int,类型的数组来模拟的堆栈:,public interface,StackInterface,public void,push(int,n);,public,int,pop();,共享数据出错例子(示例,12-8,),public class,UnsafeStack,implements,StackInterface,private,int,top = 0;,private,int, values = new int10;,public void,push(int,n) ,valuestop = n;/1,System.out.println,(,压入数字,+n+,步骤,1,完成,);,top+;/2,System.out.println,(,压入数字完成,);,public,int, pop() ,System.out.print(,弹出,);,top-;/3,int, test = valuestop,top;/4,return test;,共享数据出错例子,(,con.,),public class,TestUnsafeStack,public static void main(String,args,),UnsafeStack,s = new,UnsafeStack,();,s.push(1);/5,s.push(2);/6,PushThread,r1 = new,PushThread(s,);,PopThread,r2 = new,PopThread(s,);,Thread t1 = new Thread(r1);,Thread t2 = new Thread(r2);,t1.start();/7,t2.start();/8,共享数据出错例子(,con.,),语句,5,:,1 /top=1,语句,6,:,12 /top=2,语句,7,:启动压栈(,push,),线程,t1,语句,8,:启动出栈(,pop,),线程,t2,语句,1,:,1215 /top=2,语句,2,:,1215 /top=3,语句,3,:,1215 /top=2,语句,4,:,12 /top=2,共享数据出错例子(,con.,),语句,5,:,1 /top=1,语句,6,:,12 /top=2,语句,7,:启动压栈(,push,),线程,t1,语句,8,:启动出栈(,pop,),线程,t2,语句,1,:,1215 /top=2,语句,3,:,1215 /top=1,语句,4,:,115 /top=1,语句,2,:,115 /top=2,互斥锁,在,Java,语言中,引入了对象互斥锁(,mutual exclusive lock,,,也简称为对象锁)的概念,来保证共享数据操作的完整性:,每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。,关键字,synchronized,来与对象的互斥锁联系。当某个对象用,synchronized,修饰时,表明该对象在任一时刻只能由一个线程访问。,关键字,synchronized,在,Java,中的两种使用,synchronized,的方式:,放在方法前面,这样,调用该方法的线程均将获得对象的锁。,放在代码块前面,它也有两种形式:,synchronized (this) ,或,synchronized ,:,代码块中的代码将获得当前对象引用的锁,synchronized(otherObj,) ,:,代码块中的代码将获得指定对象引用的锁,释放锁,如果一个线程一直占用一个对象的锁,则其他的线程将永远无法访问该对象,因此,需要在适当的时候,将对象锁归还。,当线程执行到,synchronized(),块结束时,释放对象锁。,当在,synchronized(),块中遇到,break, return,或抛出,exception,,,则自动释放对象锁。,当一个线程调用,wait(),方法时,它放弃拥有的对象锁并进入等待队列。,synchronized,例子(示例,12-8,),public void,push(int,n) ,synchronized(this),valuestop = n;,System.out.println,(,压入数字,+n+,步骤,1,完成,);,top+;,System.out.println,(,压入数字完成,);,public,int, pop(),synchronized(this),System.out.print(,弹出,);,top-;,int, test = valuestop,top;,return test;,死锁,是指两个线程,都相互等待对方释放,lock,是不可测知或避开的,应采取措施避免死锁的出现,对象的,wait(),、,notify(),和,notifyAll,(),方法,Object,类定义了,wait(),、,notify(),和,notifyAll,(),方法。可以让线程相互通知事件的发生。要执行这些方法,必须拥有相关对象的锁。,wait(),会让调用线程休眠,直到用,Thread.interrupt(),中断它、过了指定的时间、或者另一个线程用,notify(),或,notifyAll,(),唤醒它。,当对某个对象调用,notify(),时,如果有任何线程正在通过,wait(),等待该对象,那么就会唤醒其中一个线程。当对某个对象调用,notifyAll,(),时,会唤醒所有正在等待该对象的线程。,实现了线程通信的堆栈类(示例,12-9,),public void push(,int,n) ,synchronized(this) ,while(,dataAvailable,) /1,try ,wait();,catch(,InterruptedException,e) /,忽略,/2,valuestop = n;,System.out.,println,(,压入数字,+,n+,步骤,1,完成,);,top+;,dataAvailable,= true;,notifyAll,();,System.out.,println,(,压入数字完成,);,实现了线程间通信的堆栈类(,con.,),public,int, pop() ,synchronized(this) ,while(!,dataAvailable,) /3,try ,wait();,catch(,InterruptedException,e) /,忽略,/4,System.out.print(,弹出,);,top-;,int, test = valuestop,top;,dataAvailable,= false;,notifyAll,();,return test;,避免无谓的同步方法,因为同步会降低程序的执行效率,所以应该避免无谓的同步,通过所谓的,Fine-Grained,锁的机制,可以避免这种情况,多线程编程一般规则,如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的,如果对象更新影响到只读方法,那么只读方法也要定义成同步的。,不要滥用同步。如果在一个对象内的不同的方法访问的不是同一个数据,就不要将方法设置为,synchronized,的。,如果一个线程必须等待一个对象状态发生变化,那么他应该在对象内部等待,而不是在外部。他可以通过调用一个被同步的方法,并让这个方法调用,wait(),。,每当一个方法返回某个对象的锁时,它应当调用,notifyAll,(),来让等待队列中的其他线程有机会执行。,记住,wait(),和,notify()/,notifyAll,(),是,Object,类方法,而不是,Thread,类的方法。仔细查看每次调用,wait(),方法,都有相应的,notify()/,notifyAll,(),方法,且它们均作用于同一个对象。,多线程编程一般规则(,con.,),针对,wait(),、,notify()/,notifyAll,(),使用旋锁(,spin lock,);,优先使用,notifyAll,(),而不是,notify(),;,按照固定的顺序获得多个对象锁,以避免死锁;,不要对上锁的对象改变它的引用;,不要滥用同步机制,避免无谓的同步控制。,小结,线程的概念模型,线程的创建和启动,线程的状态控制,多线程,对象锁和死锁,线程的互斥和同步,wait(),、,notify()/,notifyAll,(),多线程编程的一般规则,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!