首页 线程同步

线程同步

举报
开通vip

线程同步线程同步 多线程编程 -wait(),notify()/notityAll()方法 关于这两个方法,有很多的内容需要说明.在下面的说明中可能会有很多地方不能一下子 明白,但在看完本节后,即使不能完全明白,你也一定要回过头来记住下面的两句话: [wait(),notify()/notityAll()方法是普通对象的方法(Object超类中实现),而不是线程对象的方法] [wait(),notify()/notityAll()方法只能在同步方法中调用] [线程的互斥控制] 多个线程同时操作某一对象时,一个线...

线程同步
线程同步 多线程编程 -wait(),notify()/notityAll()方法 关于这两个方法,有很多的内容需要说明.在下面的说明中可能会有很多地方不能一下子 明白,但在看完本节后,即使不能完全明白,你也一定要回过头来记住下面的两句话: [wait(),notify()/notityAll()方法是普通对象的方法(Object超类中实现),而不是线程对象的方法] [wait(),notify()/notityAll()方法只能在同步方法中调用] [线程的互斥控制] 多个线程同时操作某一对象时,一个线程对该对象的操作可能会改变其状态,而该状态会影响另一线程对该对象的真正结果. 这个例子我们在太多的文档中可以看到,就象两个售票员同时售出同一张票一样. 线程A 线程B 1.线程A在数据库中查询存票,发现票C可以卖出 2.线程A接受用户订票请求,准备出票. 3. 这时切换到了线程B执行 4. 线程B在数据库中查询存票,发现票C可以卖出 5. 线程B将票卖了出去 6.切换到线程A执行,线程A卖了一张已经卖出的票 所以需要一种机制来管理这类问题的发生,当某个线程正在执行一个不可分割的部分时,其它线程不能同时执行这一部分. 像这种控制某一时刻只能有一个线程执行某个执行单元的机制就叫互斥控制或共享互斥(mutual exclusion) 在JAVA中,用synchornized关键字来实现互斥控制(暂时这样认为,JDK1.5已经发展了新的机制) [synchornized关键字] 把一个单元声明为synchornized,就可以实现在同一时间只有一个线程操作该方法. 事实上synchornized就是一把锁,但是是谁的锁,锁谁,这是一个非常复杂的问题. 每个对象只有一把监视锁(monitor lock),一次只能被一个线程获取.当一个线程获取了这一个锁后,其它线程就只能等待这个线程释放该锁后才能再获取该锁. 那么synchornized关键字到底锁什么?得到了谁的锁? 对于同步块,synchornized获取的是参数中的对象的锁: synchornized(obj){ //............... } 线程执行到这里时,首先要获取obj这个实例的锁,如果没有获取到,线程只能等待.如果多 个线程执行到这里,只能有一个线程获取obj的锁,然后执行{}中的语句,所以,obj对象的作 用范围不同,控制程序不同. 假如: class Test{ public void test(){ Student stu = new Student(); synchornized(stu){ //............... } } , 这段程序实现不了同步,没有实现多线程之间的资源共享。因为每个线程执行到 Student stu = new Student()时会各自产生一个新对象然后获取这个对象有监视锁,各自皆大欢喜地 执行 而如果是类的属性: class Test{ Student stu = new Student(); public void test(){ synchornized(stu){ //............... } } } 所有执行到Test实例的synchornized(o)的线程,只有一个线程可以获取到监视锁,实现 线程的同步,多个线程共享一个stu对象 有时我们会这样: public void test(){ synchornized(this){ //............... } } 那么所有执行Test实例的线程只能有一个线程执行.而synchornized(o)和 synchornized(this)的范围是不同的,因为执行到Test实例的synchornized(o)的线程等待时,其它线程可以执行Test实例的synchornized(o1)部分,但多个线程同时只有一个可以执行Test实例的synchornized(this). 而对于 synchornized(Test.class){ //............... }这样的同步块而言,所有调用Test多个实例的线程此时只能有一个线程可以执行. [synchornized方法] 如果一个方法声明为synchornized的,则等同于在这个方法上调用synchornized(this). 如果一个静态方法被声明为synchornized,则等同于在这个方法上调用synchornized(类.class). 现在进入wait方法和notify/notifyAll方法.这两个(或叫三个)方法都是Object对象的方法,而不是线程对象的方法.如同锁一样,它们是在线程中调用某一对象上执行的. class Test{ public synchornized void test(){ //获取条件,int x 要求大于100; if(x < 100) wait(); } } 这里为了说明方法没有加在try{}catch(){}中,如果没有明确在哪个对象上调用wait()方法,则为this.wait(); 假如: Test t = new Test(); 现在有两个线程都执行到t.test();方法.其中线程A获取了t的对象锁,进入test()方法内.这时x小于100,所以线程A进入等待. 当一个线程调用了wait方法后,这个线程就进入了这个对象的休息室(waitset),这是一个虚拟的对象,但JVM中一定存在这样的一个数据结构用来 记录 混凝土 养护记录下载土方回填监理旁站记录免费下载集备记录下载集备记录下载集备记录下载 当前对象中有哪些程线程在等待. 当一个线程进入等待时,它就会释放锁,让其它线程来获取这个锁. 所以线程B有机会获得了线程A释放的锁,进入test()方法,如果这时x还是小于100,线程B也进入了t的休息室.这两个线程只能等待其它线程调用notity[All]来唤醒. 但是如果调用的是有参数的wait(time)方法,则线程A,B都会在休息室中等待这个时间后自动唤醒. [为什么真正的应用都是用while(条件)而不用if(条件)] 在实际的编程中我们看到大量的例子都是用 while(x < 100) wait(); go();而不是用if,为什么呢? 在多个线程同时执行时,if(x <100)是不安全的.因为如果线程A和线程B都在t的休息室中等待, 这时另一个线程使x==100了,并调用notifyAll方法,线程A继续执行下面的go().而它执行完成后,x有可能 又小于100,比如下面的程序中调用了--x,这时切换到线程B,线程B没有继续判断,直接执行go();就产生一个 错误的条件,只有while才能保证线程B又继续检查一次. [notify/notifyAll方法] 这两个方法都是把某个对象在休息区内的线程唤醒,notify只能唤醒一个,但究竟是哪一个不能确定,而notifyAll则唤醒这个对象上的休息室中所有的线程. 一般为了安全性,我们在绝对多数时候应该使用notifiAll(),除非你明确知道只唤醒其中的一个线程. 那么是否是只要调用一个对象的wait()方法,当前线程就进入了这个对象的休息室呢?事实中,要调用一个对象的wait()方法,只有当前线程获取了这个对象的锁,换句话说一定要在这个对象的同步方法或以这个对象为参数的同步块中. class MyThread extends Thread{ Test t = new Test(); public void run(){ t.test(); System.out.println("Thread say:Hello,World!"); } } public class Test { int x = 0; public void test(){ if(x==0) try{ wait(); }catch(Exception e){} } public static void main(String[] args) throws Exception{ new MyThread().start(); } } 这个线程就不会进入t的wait方法而直接打印出Thread say:Hello,World!. 而如果改成: public class Test { int x = 0; public synchornized void test(){ if(x==0) try{ wait(); }catch(Exception e){} } public static void main(String[] args) throws Exception{ new MyThread().start(); } } 我们就可以看到线程一直等待,注意这个线程进入等待后没有其它线程唤醒,除非强行退出 JVM环境,否则它一直等待. 所以请记住: 1,线程要想调用一个对象的wait()方法就要先获得该对象的监视锁,而一旦调用wait()后又 立即释放该锁 2,如果要把notify/notifyAll和wait方法放在一起用的话,必须先调用notify/notifyAll后调用wait,因为如果调用完wait,该线程就已 经不是current thread了 3,wait(),notify(),notifyAll()方法必须出现在同步方法或同步代码块中
本文档为【线程同步】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_477730
暂无简介~
格式:doc
大小:21KB
软件:Word
页数:8
分类:
上传时间:2018-11-21
浏览量:14