当线程A调用wait()方法后,被线程B调用java wait notifyy(),问:线程A是重新执行?还是从断点处继续执行?

Java(46)
在Java中,所有对象都能够被作为&监视器monitor&——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity。所有对象的非同步方法都能够在任意时刻被任意线程调用,此时不需要考虑加锁的问题。而对于对象的同步方法来说,在任意时刻有且仅有一个拥有该对象独占锁的线程能够调用它们。例如,一个同步方法是独占的。如果在线程调用某一对象的同步方法时,对象的独占锁被其他线程拥有,那么当前线程将处于阻塞状态,并添加到对象的入口队列中。
只有在调用线程拥有某个对象的独占锁时,才能够调用该对象的wait(),notify()和notifyAll()方法。这一点通常不会被程序员注意,因为程序验证通常是在对象的同步方法或同步代码块中调用它们的。如果尝试在未获取对象锁时调用这三个方法,那么你将得到一个&java.lang.IllegalMonitorStateException:current thread not owner&。
当一个线程正在某一个对象的同步方法中运行时调用了这个对象的wait()方法,那么这个线程将释放该对象的独占锁并被放入这个对象的等待队列。注意,wait()方法强制当前线程释放对象锁。这意味着在调用某对象的wait()方法之前,当前线程必须已经获得该对象的锁。因此,线程必须在某个对象的同步方法或同步代码块中才能调用该对象的wait()方法。
当某线程调用某对象的notify()或notifyAll()方法时,任意一个(对于notify())或者所有(对于notifyAll())在该对象的等待队列中的线程,将被转移到该对象的入口队列。接着这些队列(译者注:可能只有一个)将竞争该对象的锁,最终获得锁的线程继续执行。如果没有线程在该对象的等待队列中等待获得锁,那么notify()和notifyAll()将不起任何作用。在调用对象的notify()和notifyAll()方法之前,调用线程必须已经得到该对象的锁。因此,必须在某个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法。
对于处于某对象的等待队列中的线程,只有当其他线程调用此对象的notify()或notifyAll()方法时才有机会继续执行。
调用wait()方法的原因通常是,调用线程希望某个特殊的状态(或变量)被设置之后再继续执行。调用notify()或notifyAll()方法的原因通常是,调用线程希望告诉其他等待中的线程:&特殊状态已经被设置&。这个状态作为线程间通信的通道,它必须是一个可变的共享状态(或变量)。
例如,生产者线程向缓冲区中写入数据,消费者线程从缓冲区中读取数据。消费者线程需要等待直到生产者线程完成一次写入操作。生产者线程需要等待消费者线程完成一次读取操作。假设wait(),notify(),notifyAll()方法不需要加锁就能够被调用。此时消费者线程调用wait()正在进入状态变量的等待队列(译者注:可能还未进入)。在同一时刻,生产者线程调用notify()方法打算向消费者线程通知状态改变。那么此时消费者线程将错过这个通知并一直阻塞。因此,对象的wait(),notify(),notifyAll()方法必须在该对象的同步方法或同步代码块中被互斥地调用。
三。 wait()与sleep()的区别
sleep()方法是Thread类的静态方法,不涉及到线程间同步概念,仅仅为了让一个线程自身获得一段沉睡时间。sleep可以在任何地方使用。
wait()方法是object类的方法,解决的问题是线程间的同步,该过程包含了同步锁的获取和释放,调用wait方法将会将调用者的线程挂起,直到其他线程调用同一个对象的notify()方法才会重新激活调用者。
注意:线程调用notify()之后,只有该线程完全从
synchronized代码里面执行完毕后,monitor才会被释放,被唤醒线程才可以真正得到执行权。
&今天同学写个手机游戏,用蓝牙传输数据的时候丢包,问我解决方案,我提出的方案是:用多线程发送数据并要求对方回送ack号,如果在一定时间内没收到就要重发,如果收到了就要自身wait,那么这要用到多线了,开始写了几个老是报错,就在网上找了找这方面的资料,终于解决了,呵呵!下面我把这篇写的比较全面的文章转载过来,做个笔记,希望能帮助更多的用多线程出现问题的朋友们。
wait与notify是java同步机制中重要的组成部分。结合与synchronized关键字使用,可以建立很多优秀的同步模型。
&&&&& synchronized(this){}等价与public synchronized void method(){.....}
&&&&& 同步分为类级别和对象级别,分别对应着类锁和对象锁。类锁是每个类只有一个,如果static的方法被synchronized关键字修饰,则在这个方法被执行前必须获得类锁;对象锁类同。
&&&&& 首先,调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在作用等同于synchronized(obj){......}的内部才能够去调用obj的wait与notify/notifyAll三个方法,否则就会报错:
&&&&& java.lang.IllegalMonitorStateException: current thread not owner
&&&&& 在调用wait的时候,线程自动释放其占有的对象锁,同时不会去申请对象锁。当线程被唤醒的时候,它才再次获得了去获得对象锁的权利。
&&&&& 所以,notify与notifyAll没有太多的区别,只是notify仅唤醒一个线程并允许它去获得锁,notifyAll是唤醒所有等待这个对象的线程并允许它们去获得对象锁,只要是在synchronied块中的代码,没有对象锁是寸步难行的。其实唤醒一个线程就是重新允许这个线程去获得对象锁并向下运行。
&&&&&& 顺便说一下notifyall,虽然是对每个wait的对象都调用一次notify,但是这个还是有顺序的,每个对象都保存这一个等待对象链,调用的顺序就是这个链的顺序。其实启动等待对象链中各个线程的也是一个线程,在具体应用的时候,需要注意一下。
class ThreadA
&&& public static void main(String[] args)
&&&&& ThreadB b=new ThreadB();
&&&&& b.start();
&&&&& System.out.println(&b is start....&);
&&&&& synchronized(b)//括号里的b是什么意思,起什么作用?
&&&&&&& try
System.out.println(&Waiting for b to complete...&);
b.wait();//这一句是什么意思,究竟让谁wait?
&&&&&&&&& System.out.println(&Completed.Now back to main thread&);
&&&&&&& }catch (InterruptedException e){}
&&&&& System.out.println(&Total is :&+b.total);
class ThreadB extends Thread
&&& public void run()
&&&&& synchronized(this)
&&&&&&& System.out.println(&ThreadB is running..&);
&&&&&&& for (int i=0;i&100;i++ )
&&&&&&&&& total +=i;
&&&&&&&&& System.out.println(&total is &+total);
&&&&&&& notify();
要分析这个程序,首先要理解notify()和wait(),为什么在前几天纪录线程的时候没有纪录这两个方法呢,因为这两个方法本来就不属于Thread类,而是属于最底层的object基础类的,也就是说不光是Thread,每个对象都有notify和wait的功能,为什么?因为他们是用来操纵锁的,而每个对象都有锁,锁是每个对象的基础,既然锁是基础的,那么操纵锁的方法当然也是最基础了.
再往下看之前呢,首先最好复习一下Think in Java的14.3.1中第3部分内容:等待和通知,也就是wait()和notify了.
按照Think in Java中的解释:&wait()允许我们将线程置入“睡眠”状态,同时又“积极”地等待条件发生改变.而且只有在一个notify()或notifyAll()发生变化的时候,线程才会被唤醒,并检查条件是否有变.&
&&& 我们来解释一下这句话.
&&& &wait()允许我们将线程置入“睡眠”状态&,也就是说,wait也是让当前线程阻塞的,这一点和sleep或者suspend是相同的.那和sleep,suspend有什么区别呢?
&&&& 区别在于&(wait)同时又“积极”地等待条件发生改变&,这一点很关键,sleep和suspend无法做到.因为我们有时候需要通过同步(synchronized)的帮助来防止线程之间的冲突,而一旦使用同步,就要锁定对象,也就是获取对象锁,其它要使用该对象锁的线程都只能排队等着,等到同步方法或者同步块里的程序全部运行完才有机会.在同步方法和同步块中,无论sleep()还是suspend()都不可能自己被调用的时候解除锁定,他们都霸占着正在使用的对象锁不放.
&&&& 而wait却可以,它可以让同步方法或者同步块暂时放弃对象锁,而将它暂时让给其它需要对象锁的人(这里应该是程序块,或线程)用,这意味着可在执行wait()期间调用线程对象中的其他同步方法!在其它情况下(sleep啊,suspend啊),这是不可能的.
&&&& 但是注意我前面说的,只是暂时放弃对象锁,暂时给其它线程使用,我wait所在的线程还是要把这个对象锁收回来的呀.wait什么?就是wait别人用完了还给我啊!
&&&& 好,那怎么把对象锁收回来呢?
&&&& 第一种方法,限定借出去的时间.在wait()中设置参数,比如wait(1000),以毫秒为单位,就表明我只借出去1秒中,一秒钟之后,我自动收回.
&&&& 第二种方法,让借出去的人通知我,他用完了,要还给我了.这时,我马上就收回来.哎,假如我设了1小时之后收回,别人只用了半小时就完了,那怎么办呢?靠!当然用完了就收回了,还管我设的是多长时间啊.
&&&& 那么别人怎么通知我呢?相信大家都可以想到了,notify(),这就是最后一句话&而且只有在一个notify()或notifyAll()发生变化的时候,线程才会被唤醒&的意思了.
&&&& 因此,我们可将一个wait()和notify()置入任何同步方法或同步块内部,无论在那个类里是否准备进行涉及线程的处理。而且实际上,我们也只能在同步方法或者同步块里面调用wait()和notify().
&&&& 这个时候我们来解释上面的程序,简直是易如反掌了.
&&&& synchronized(b){...};的意思是定义一个同步块,使用b作为资源锁。b.wait();的意思是临时释放锁,并阻塞当前线程,好让其他使用同一把锁的线程有机会执行,在这里要用同一把锁的就是b线程本身.这个线程在执行到一定地方后用notify()通知wait的线程,锁已经用完,待notify()所在的同步块运行完之后,wait所在的线程就可以继续执行
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
(3)(51)(17)(65)(21)(10)(25)(52)(15)(10)(5)(14)(8)(14)(70)(44)(32)(98)(119)(15)java线程中的wait()和notify()的疑惑(我查过资料,还是不懂
[问题点数:40分,结帖人linsenlinwei]
java线程中的wait()和notify()的疑惑(我查过资料,还是不懂
[问题点数:40分,结帖人linsenlinwei]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。多线程的问题wait,notify
[问题点数:20分,结帖人tayanxunhua]
多线程的问题wait,notify
[问题点数:20分,结帖人tayanxunhua]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。通常,多线程之间需要协调工作。例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线程downloadThread将该图片下载完毕。如果图片还没有下载完,displayThread可以暂停,当downloadThread完成了任务后,再通知displayThread&图片准备完毕,可以显示了&,这时,displayThread继续执行。
  以上逻辑简单的说就是:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。例如:
  synchronized(obj) {
   & while(!condition) {
  &  obj.wait();
& obj.doSomething();
当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。
  在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:
 synchronized(obj) {
  condition =
  obj.notify();
 需要注意的概念是:
 # 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。
 # 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。
 # 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。
 # 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。
  # obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。
  # 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:14065次
排名:千里之外
原创:28篇
转载:12篇
评论:19条
(17)(1)(5)(4)(2)(11)

我要回帖

更多关于 java wait notify 的文章

 

随机推荐