Java多线程之wait(),notify(),notifyAll()

在多线程的情况下,因为同一进程的多个线程共享同一片存储空间,在带来方便的同一时候,也带来了訪问冲突这个严重的问题。Java语言提供了专门机制以解决这样的冲突,有效避免了同一个数据对象被多个线程同一时候訪问。

wait与notify是java同步机制中重要的组成部分。结合与synchronizedkeyword使用,能够建立非常多优秀的同步模型。

synchronized(this){ }等价于publicsynchronized void method(){.....}

同步分为类级别和对象级别,分别相应着类锁和对象锁。类锁是每一个类仅仅有一个,假设static的方法被synchronizedkeyword修饰,则在这种方法被运行前必须获得类锁;对象锁类同。

首先,调用一个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,可是这个还是有顺序的,每一个对象都保存这一个等待对象链,调用的顺序就是这个链的顺序。事实上启动等待对象链中各个线程的也是一个线程,在详细应用的时候,须要注意一下。

wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每一个对像都有wait(),notify(),notifyAll()的功能。由于都个对像都有锁,锁是每一个对像的基础,当然操作锁的方法也是最基础了。

wait():

等待对象的同步锁,须要获得该对象的同步锁才干够调用这种方法,否则编译能够通过,但执行时会收到一个异常:IllegalMonitorStateException。

调用随意对象的 wait() 方法导致该线程堵塞,该线程不可继续运行,而且该对象上的锁被释放。

notify():

唤醒在等待该对象同步锁的线程(仅仅唤醒一个,假设有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,并且不是按优先级。

调用随意对象的notify()方法则导致因调用该对象的 wait()方法而堵塞的线程中随机选择的一个解除堵塞(但要等到获得锁后才真正可运行)。

notifyAll():

唤醒全部等待的线程,注意唤醒的是notify之前wait的线程,对于notify之后的wait线程是没有效果的。

通常,多线程之间须要协调工作:假设条件不满足,则等待;当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。

比如:

  synchronized(obj) {

  while(!condition) {

  obj.wait();

  }

  obj.doSomething();

  }

  

  当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。

  在还有一线程B中,假设B更改了某些条件,使得线程A的condition条件满足了,就能够唤醒线程A :

  

  synchronized(obj) {

  condition = true;

  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中的一个才有机会获得锁继续运行。

  

谈一下synchronized和wait()、notify()等的关系:

1.有synchronized的地方不一定有wait,notify

2.有wait,notify的地方必有synchronized.这是由于wait和notify不是属于线程类,而是每个对象都具有的方法,并且,这两个方法都和对象锁有关,有锁的地方,必有synchronized。

另外,注意一点:假设要把notify和wait方法放在一起用的话,必须先调用notify后调用wait,由于假设调用完wait,该线程就已经不是currentthread了。

Java多线程之wait(),notify(),notifyAll(),布布扣,bubuko.com

时间: 2024-12-25 14:36:54

Java多线程之wait(),notify(),notifyAll()的相关文章

java 多线程之wait(),notify,notifyAll(),yield()

wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对像都有wait(),notify(),notifyAll()的功能.因为都个对像都有锁,锁是每个对像的基础,当然操作锁的方法也是最基础了. wait与notify是java同步机制中重要的组成部分.结合与synchronized关键字使用,可以建立很多优秀的同步模型.   synchronized(this){ }等价于publicsynchronized void method

JAVA多线程之wait/notify

本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait() 与  notify/notifyAll() 的执行过程 ③中断 调用wait()方法进入等待队列的 线程 ④notify 通知的顺序不能错 ⑤多线程中测试某个条件的变化用 if 还是用 while? ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 wait()

Java多线程之Wait()和Notify()

1.Wait()和Notify.NotifyAll都是Object的方法 2.多线程的协作是通过控制同一个对象的Wait()和Notify()完成 3.当调用Wait()方法时,当前线程进入阻塞状态,直到有另一线程调用了该对象的Notify()方法 package Thread.Wait; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.con

Java多线程之notifyAll的作用域

notifyAll()因某个特定锁而被调用时,只有等待这个锁的任务才会被唤醒. package Thread.Wait; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; class Blocker { synchronized void waitingCall() { try

java多线程之ThreadLocal

ThreadLocal保证数据同步 package Thread.Common; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; class Accessor implements Runnable { private final int id; pub

java多线程之Future和FutureTask

Executor框架使用Runnable 作为其基本的任务表示形式.Runnable是一种有局限性的抽象,然后可以写入日志,或者共享的数据结构,但是他不能返回一个值. 许多任务实际上都是存在延迟计算的:执行数据库查询,从网络上获取资源,或者某个复杂耗时的计算.对于这种任务,Callable是一个更好的抽象,他能返回一个值,并可能抛出一个异常.Future表示一个任务的周期,并提供了相应的方法来判断是否已经完成或者取消,以及获取任务的结果和取消任务. public interface Callab

Java多线程之join

将另外一个线程join到当前线程,则需要等到join进来的线程执行完才会继续执行当前线程. package Thread.join; class Sleeper extends Thread { private int duration; public Sleeper(String name, int sleepTime) { super(name); duration = sleepTime; start(); } public void run() { try { sleep(duratio

Java多线程之DaemonThreadFactory

通过DaemonThreadFactory创建后台线程池 另外:如果是后台线程创建的线程,将都是后台线程. package wzh.daemon; import java.util.concurrent.ThreadFactory; public class DaemonThreadFactory implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r);

JAVA多线程之volatile 与 synchronized 的比较

一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空间???线程执行时,先把变量从主内存读取到线程自己的本地内存空间,然后再对该变量进行操作 ②对该变量操作完后,在某个时间再把变量刷新回主内存 关于JAVA内存模型,更详细的可参考: 深入理解Java内存模型(一)——基础 因此,就存在内存可见性问题,看一个示例程序:(摘自书上) 1 public c