关于Java wait()方法
来源:互联网 发布:耳环饰品淘宝推荐 编辑:程序博客网 时间:2024/06/05 15:52
每一个对象除了有一个锁之外,还有一个等待队列(wait set),当一个对象刚创建的时候,它的等待队列是空的。
我们应该在某个线程获取对象的锁后,在该对象锁控制的同步块或同步方法中去调用该对象的wait方法,将该线程挂起放入该对象等待队列。
当调用该对象的notify方法时,将从该对象的等待队列中随机唤醒一个线程,这个线程将再次成为可运行的线程。
所以我们使用wait和notify方法的时候必须确定这两个线程在同一个对象(必须是控制该同步块或同步方法的对象)的等待队列。
=====================================
wait() 是否会导致死锁?
wait()和notifyAll()提供了线程协作的方式(另外一种是线程互斥的方式),会不会出现死锁的现象?[解释一下协作:A线程需要达到某种状
态S才能继续工作,但是暂时S状态不能由A线程本身满足,所以A线程必须等待S状态的满足(wait);另外的线程B可以达到S状态,当S状态达到
的时候,B可以通知A线程继续(notify),这就是所谓的协作方式。最典型的应用可以是一个队列,有数个线程向队列中增加数据,有数个线程
处理队列中的数据。appender线程和handler线程需要协作]
Java本身的线程机制比较完善,单独从wait机制和notify机制来说,是不会造成死锁的。当线程调用wait,它会释放monitor,并进入等待区。
当等待区中的线程被notify唤醒,它会竞争monitor的锁。得到monitor的线程(持有者)只会有一个。
所以说,单纯的wait和notify机制已经在jvm实现中避免了死锁的情况。
但是,话说来,出现死锁的地方实际上还是由于代码的缺陷所造成的。当然有可能造成死锁。俺们主要可以讨论一个wait的两个关键问题:
(1) DeadLock问题
(2) wait条件问题
先来看DeadLock问题,借用EffectiveJava中的一个例子,下例就可以造成死锁。
<<
public abstract class WorkQueue {
private final List queue = new LinkedList();
private boolean stopped = false;
protected WorkQueue() {
new WorkerThread().start();
}
public final void enqueue(Object workItem) {
synchronized (queue) {
queue.add(workItem);
queue.notify();
}
}
public final void stop() {
synchronized (queue) {
stopped = true;
queue.notify();
}
}
protected abstract void processItem(Object workItem)
throws InterruptedException;
// Broken - invokes alien method from synchronized block!
private class WorkerThread extends Thread {
public void run() {
while (true) { // Main loop
synchronized (queue) {
try {
while (queue.isEmpty() && !stopped)
queue.wait();
} catch (InterruptedException e) {
return;
}
if (stopped)
return;
Object workItem = queue.remove(0);
try {
processItem(workItem); // Lock held!
} catch (InterruptedException e) {
return;
}
}
}
}
}
}
>>
这是一个用LinkedList来实现的队列的例子。enqueue方法向队列中增加元素并通知处理线程,而处理线程代码如WorkerThread所示,从队列中
取出元素并处理,如果队列为空,则等待直到enqueue或者stop方法唤醒它。<<queue.wait();>>。
这个思路好像没有问题,问题在于它把处理流程(synchronized中)做成了抽象:protected abstract void processItem(Object workItem),
这样就把一些问题留给了子类,就有可能造成死锁,比如这样的子类:
<<
class DeadlockQueue extends WorkQueue {
protected void processItem(final Object workItem)
throws InterruptedException {
// Create a new thread that returns workItem to queue
Thread child = new Thread() {
public void run() {
enqueue(workItem);
}
};
child.start();
child.join(); // Deadlock!
}
}
>>
呵呵,所以说:“死锁还是由开发者的缺陷代码所导致的”。
这个故事告诉俺们:“不要把synchronized块代码的控制交给客户端”。:)
第二个问题wait条件问题,可以这么看:在等待区中的线程丛被唤醒到持有monitor锁,这中间是有时延的。并不能保证在这期间,有其他的线
程持有锁。刚才说了,需要S状态A线程才能继续,现在B线程使S状态被满足并通知了等待中的A。但是在A获取锁之前,有一个C线程抢先获取了
锁,而C线程破坏了S状态。等待A线程获取锁的时候,S状态已经不满足了,但是A线程并不知道这点,可能还是会继续处理。问题当然就可以产
生了。
解决这个问题的办法就是,让等待的线程获取锁的时候一定要检查数据状态,如果不满足,呵呵,继续等待。
所以这个问题告诉俺们:“不要在循环外面调用wait方法”
为什么要在循环内呢?因为要让循环的条件作为状态的检查条件。
- 关于Java wait()方法
- 关于Java中的sleep和wait方法
- 关于线程wait方法
- 关于java中wait()和sleep()方法间的区别
- 关于java中sleep()和wait()方法的区别
- Java中的wait方法
- Java Object.wait()方法
- Java Thread.wait方法
- 关于 JAVA wait()和notify()
- java 关于wait 和notify
- Java中wait,notify方法
- java 线程 wait() notify() 方法
- java对象方法wait,notify
- 列关于java 中的 wait()方法和 sleep()方法的区别描述错误的是?
- 关于wait和sleep方法的区别
- Java中多线程关于wait()和notify()方法的小错误备忘录
- 关于java多线程中的wait和sleep方法和临界区的概念
- java关于线程的sleep(),yield(),join(),wait(),notify(),notifyAll()等方法的总结
- 【序列】乘法——直接举个“栗子”
- Android弹幕功能实现,模仿斗鱼直播的弹幕效果
- 模拟select下拉框,解决ie9以下不支持替换小箭头
- ORACLE使用row_number() over(...)对查询数据进行分组并排序
- WebStorm设置JSX
- 关于Java wait()方法
- 基于软件的负载均衡(Nginx与ZooKeeper解析)
- 【Bzoj2151】种树
- AngularJS 核心概览
- .net 解析Transfer-Encoding:chunked 秒掉网上无用方案
- java 整合redis缓存 SSM 后台框架 rest接口 shiro druid maven
- 加载本地HTML文件
- Java基本数据类型
- zookeeper入门系列-理论基础-分布式事务