我们先看看代码片段,有点类似生产者-消费者模型中的生产者的逻辑代码。
public synchronized void push(Object obj){
while( condition ){
try{
this.wait(); //等待,直到有数据出栈
}catch(InterruptedException e){
}
}
//do something
stack.push(obj);
this.notify(); //通知其它线程把数据出栈
}
注意第4行,代码执行到这里会发生什么状态?
push方法的签名中有synchronized修饰,所以此方法具有排他性,锁(资源)为自身实例对象,也就是说同时同一个对象的这个方法只能被一个线程所执行,那么当执行到第4行时会发生什么呢? XX一紧,线程在释放排他锁资源之前,自己把自己给阻塞了? 这样岂不是死锁了?
翻翻JDK1.6手册,便恍然大悟:
wait方法共有3个重载函数:
- public final void wait(long timeout)
throws InterruptedException
- public final void wait(long timeout, int nanos) throws InterruptedException
- public final void wait() throws InterruptedException
在其他线程调用此对象的
notify()
方法或
notifyAll()
方法,或者超过指定的时间量前,导致当前线程等待。此方法导致当前线程(称之为
T)将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。出于线程调度目的,在发生以下四种情况之一前,线程
T 被禁用,且处于休眠状态:
- 其他某个线程调用此对象的 notify 方法,并且线程 T 碰巧被任选为被唤醒的线程。
- 其他某个线程调用此对象的 notifyAll 方法。
- 其他某个线程中断线程
T。
- 大约已经到达指定的实际时间。但是,如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。
然后,从对象的等待集中删除线程
T,并重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被恢复到以前的状态,这就是调用
wait 方法时的情况。然后,线程 T 从 wait 方法的调用中返回。所以,从
wait 方法返回时,该对象和线程 T 的同步状态与调用 wait 方法时的情况完全相同。
简而言之:
- wait方法的作用释放已持有的锁,并进入休眠状态;当被唤醒或是等待超时,当前的线程又会重新加入到锁等待队列中,一旦获取了对该对象的控制权,则会从原来的地方继续执行;如果线程被中断,则会抛出InterruptedException异常。
- notify方法唤醒等待队列中的第一个线程并把它移入锁申请队列中
- notifyAll方法唤醒等待队列中的所有的线程并把它们移入锁申请队列中
- wait,notify,notifyAll必须在已经持有锁的情况下执行,所以它们只能出现在synchronized作用范围内,也就是出现在用synchronized修饰的方法或代码块中.
- 在更多线程的情况下(e.g. 拿消费者/生产者模型来讲,可能存在多个消费者和多个生产者),线程被唤醒后依然需要对条件进行测试,如果不满足该条件,则继续等待。换句话说,等待应总是发生在循环中。如上述代码示例(2-7循环体)
附上完整的示例代码:
public class ThreadDemo {
private int x = 0;
public synchronized void add() {
while (x >= 2) {
try {
this.wait();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
x++;
System.out.println("add:" + x);
this.notifyAll();
}
public synchronized void sub() {
int y = 1;
while (x < 2) {
System.out.println("sub:while repeat = " + y);
y++;
try {
this.wait(); //this.wait(1);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
x--;
System.out.println("sub:" + x);
this.notifyAll();
}
public static void main(String[] args) throws Throwable {
final ThreadDemo tt = new ThreadDemo();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; i++) {
tt.add();
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 100; i++) {
tt.sub();
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
}
}
}
}).start();
}
}
在代码第25行处,可以试着设置下等待超时时间,然后看看测试结果。
分享到:
相关推荐
通过阅读`多线程笔记.doc`和运行`threadDemo`示例代码,你可以对Java多线程有更深入的理解,并能够在实际项目中灵活运用这些知识,解决并发问题。同时,博客地址提供了更多详细内容,可以帮助你进一步探索和实践。
5. **线程通信**:wait()、notify()、notifyAll()方法的使用,以及在生产者消费者模型、哲学家就餐问题等经典示例中的应用。 6. **线程池**:ExecutorService、ThreadPoolExecutor和Future接口的理解,线程池的配置...
`wait()`使线程等待直到其他线程调用`notify()`或`notifyAll()`唤醒它;`notify()`唤醒一个等待的线程;`notifyAll()`唤醒所有等待的线程。 #### 七、线程间协作 - **join()方法**:当前线程等待另一个线程执行...
- `wait()`, `notify()`和`notifyAll()`方法用于线程间通信,需在同步环境中使用。 5. **线程通信问题** - 生产者-消费者问题:一个线程生产数据,另一个线程消费数据,需要避免生产者过度生产或消费者提前消费。...
此外,线程间的协作(如wait()、notify()和notifyAll())也是多线程编程中需要掌握的关键技巧。 总之,Java多线程技术是提升程序并发性能的重要手段,理解线程的基本概念、实现方式以及线程间的交互机制对于开发...
3. Wait() 方法:使线程进入等待状态,释放锁资源,notify() 或 notifyAll() 唤醒线程,这三个方法必须在获得对象锁的状态下使用,否则报错。 4. IO 阻塞:线程因等待 IO 操作的完成而被阻塞。 线程优先级: 线程...
1. wait()、notify()和notifyAll():这三个方法用于线程间的通信,但必须在同步环境中使用,否则抛出`IllegalMonitorStateException`。 2. `BlockingQueue`:队列实现的线程通信,如`ArrayBlockingQueue`、`...
wait()、notify()和notifyAll()方法用于线程间的通信,这些方法必须在同步块或同步方法中使用,以避免唤醒错误的线程。 3.3 高级同步工具 Java提供了一些高级同步工具,如Semaphore(信号量)、CyclicBarrier(循环...
为了避免多线程间的资源竞争问题,Java提供了同步机制,如`synchronized`关键字、`wait()`, `notify()`, `notifyAll()`方法以及`Lock`接口。此外,`java.util.concurrent`包提供了高级并发工具,如`Semaphore`, `...
4. `wait()`, `notify()`和`notifyAll()`:用于线程间的协作,必须在同步块中调用。 五、多线程的优点与挑战 1. 优点:提高系统资源利用率,提高并发性能,增强用户体验。 2. 挑战:线程安全问题、死锁和活锁风险、...
这些方法用于线程间通信,当一个线程调用`wait()`,它会释放对象的锁并等待,直到其他线程调用`notify()`或`notifyAll()`唤醒它。 Java的`java.util.concurrent`包提供了更高级的并发工具,如`Semaphore`(信号量)...
- 使用`wait()`、`notify()`和`notifyAll()`等方法可以在线程之间传递控制权。 #### 六、线程安全性和并发控制 - **线程安全性**: - 确保在多线程环境下数据的一致性。 - 通过使用线程安全的数据结构或同步...
线程间的通信可以通过wait()、notify()和notifyAll()方法实现,这些方法都定义在Object类中。但是,这些方法必须在同步控制块或方法中使用,否则会抛出IllegalMonitorStateException。此外,使用java.util....
5. **线程通信**:线程间的通信可以通过wait(), notify()和notifyAll()方法,或者使用高级API如Semaphore、BlockingQueue等实现。 6. **线程池**:线程池可以有效地管理和控制线程,避免频繁创建和销毁线程带来的...
- **notify()** 和 **notifyAll()**:唤醒一个或所有等待的线程。 #### 七、总结 本篇笔记主要介绍了Java中线程的基本概念、创建与启动、调度与优先级、状态控制以及线程同步等内容。这些基础概念和技术是Java并发...
在描述中虽然没有具体信息,但提到的博客链接(https://metaphy.iteye.com/blog/406870)可能包含了更详细的讨论,包括线程同步和通信机制,比如synchronized关键字、wait()、notify()和notifyAll()方法,以及...
wait()、notify()和notifyAll()是Object类的方法,常用于实现生产者消费者模式,线程通过这些方法进行通信,等待或唤醒其他线程。 生产者消费者模式是一种典型的线程同步场景,其中生产者线程负责生成数据,消费者...
线程间的协作常常借助于等待和通知机制,如`wait()`、`notify()`和`notifyAll()`。这些方法需要在同步块(即持有对象锁)内调用,以避免死锁。`wait()`使线程进入等待状态,直到被`notify()`或`notifyAll()`唤醒。...