• 欢迎访问天天编码网站,Java技术、技术书单、开发工具,欢迎加入天天编码
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏天天编码吧
  • 我们的淘宝店铺已经开张了哦,传送门:https://shop145764801.taobao.com/

深入讲解Java的wait()与notify()方法

Java高级 tiantian 2857次浏览 0个评论 扫描二维码

作为一门现代的高级编程语言,Java中提供和很多与多线程相关的特性。除了最基本的同步方法(synchronized methods)和同步代码块(synchronized statements)之外,还提供了用于多线程之间进行通信的 wait() 和 nitify() 机制。本文将从两个代码示例出发,详细讨论Java中的并发机制(Java concurrency)。这两个代码示例代表了非常典型的用法,如果很好地理解了它们,那么可以认为是已经掌握了Java中的 wait() 和 notify() 机制。

深入讲解Java的wait()与notify()方法

基础知识

在我们进一步深入讨论这两个方法之前,有必要补充一些重要的基础知识:
1. synchronized 关键词的作用是实现多线程之间的排他性访问,也就是权限控制。
2. 只需简单地将 synchronized 关键词添加到方法的声明语句中,就可以使该方法变成一个同步方法(线程安全方法)。然后,即使多个线程对于同一对象的该方法进行调用,同一时刻也只会有一个方法被执行。
3. 有了实现更好的性能,可以采用同步代码块的方式。采取该方式,必须指定提供排他锁的对象。注意各个同步代码块所使用的具体对象。
4. wait() 方法会导致调用该方法的线程,放弃占有监视器,进入睡眠(sleep)状态,直到某些进入到同一个监视器的其他线程,调用 notify() 唤醒该线程。
5. notify() 方法会唤醒在同一个监视器上最早调用 wait() 方法的线程。

代码示例一

public class ThreadA {
public static void main(String[] args){
ThreadB b = new ThreadB();
b.start();

synchronized(b){
try{
System.out.println("Waiting for b to complete...");
b.wait();
}catch(InterruptedException e){
e.printStackTrace();
}

System.out.println("Total is: " + b.total);
}
}
}

class ThreadB extends Thread{
int total;
@Override
public void run(){
synchronized(this){
for(int i=0; i total += i;
}
notify();
}
}
}

上面这个示例中,我们让两个线程在对象 b 上进行同步,同时,利用 wait() 和 notify() 方法完成了让 main线程 等待 ThreadB线程 先完成计算再输出结果的逻辑。输出结果如下

Waiting for b to complete...
Total is: 4950

如果我们不使用同步机制,把代码改造成如下形式:

public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
b.start();

System.out.println("Total is: " + b.total);

}
}

class ThreadB extends Thread {
int total;

@Override
public void run() {
for (int i = 0; i < 100; i++) {
total += i;
}
}
}

那么程序的输出结果就可能是 0,10,25等值,因为 线程ThreadB 还没有完成计算,main线程 就已经输出结果了。

代码示例二

这个一个更加复杂的代码示例,建议仔细参看代码中的注释信息:

class Producer extends Thread {

static final int MAXQUEUE = 5;
private Vector messages = new Vector();

@Override
public void run() {
try {
while (true) {
putMessage();
//sleep(5000);
}
} catch (InterruptedException e) {
}
}

private synchronized void putMessage() throws InterruptedException {
while (messages.size() == MAXQUEUE) {
wait();
}
messages.addElement(new java.util.Date().toString());
System.out.println("put message");
notify();
//Later, when the necessary event happens, the thread that is running it calls notify() from a block synchronized on the same object.
}

// Called by Consumer
public synchronized String getMessage() throws InterruptedException {
notify();
while (messages.size() == 0) {
wait();//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep.
}
String message = (String) messages.firstElement();
messages.removeElement(message);
return message;
}
}

class Consumer extends Thread {

Producer producer;

Consumer(Producer p) {
producer = p;
}

@Override
public void run() {
try {
while (true) {
String message = producer.getMessage();
System.out.println("Got message: " + message);
//sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public static void main(String args[]) {
Producer producer = new Producer();
producer.start();
new Consumer(producer).start();
}
}

这里的代码是一个简单的生产者-消费者模式的示例,当然,这里为了节省一个类的定义,也为了线程之间的数据传递,生产者中的 getMessage() 方法其实是 消费者的逻辑代码。

理解这个示例代码的关键在于理解 putMessage()方法 与 getMessage()方法中的 wait()方法 与 notify()方法。

putMessage() 作用 getMessage() 作用
wait() vector已满时,睡眠 wait() vector已空时,睡眠
notify() 唤醒getMessage线程 notify() 唤醒putMessage()线程

天天编码 , 版权所有丨本文标题:深入讲解Java的wait()与notify()方法
转载请保留页面地址:http://www.tiantianbianma.com/java-wait-notify.html/
喜欢 (4)
支付宝[多谢打赏]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址