java多线程notify_java 多线程 线程之间的协作 notify()和notifyAll()

使用notify()而不是notifyAll()是一种优化。使用notify()时,在众多等待同一个锁的任务中只有一个会被唤醒,因此如果你希望使用notify(),就必须保证被唤醒的是恰当的任务。另外,为了使用notify(),所有任务必须等待相同的条件,因为如果你有多个任务在等待不同的条件,那么你就不会知道是否唤醒了恰当的任务。如果使用notify(),当条件发生变化时,必须只有一个任务能够从中受益。最后,这些限制对所有可能存在的子类都必须总是起作用。如果这些规则中有任何一条不满足,那么你就必须使用notifyAll()而不是notify()。

import java.util.Timer;

import java.util.TimerTask;

import java.util.concurrent.Executor;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.TimeUnit;

/**

* 在有关Java的线程机制的讨论中,有一个令人困惑的描述:notify()将唤醒“所有正在等待的任务”。这是否意味着在程序

* 中任何地方,任何处于wait()状态中的任务都将被任何对notifyAll()的调用唤醒呢?在下面的示例中,与Task2相关的

* 代码说明了情况并非如此---事实上,当notifyAll()因某个特定锁而被调用时,只有等待这个锁的任务才会被唤醒。

*

*

* @create @author Henry @date 2016-12-21

*

*/

class Blocker {

private String name;

public Blocker(String name) {

this.name = name;

}

synchronized void waitingCall() {

try {

while (!Thread.interrupted()) {

wait();

System.out.println(Thread.currentThread() + " " + name);

}

} catch (InterruptedException e) {

// OK to exit this way

System.out.println("InterruptedException");

}

}

synchronized void prod() {

notify();

}

synchronized void prodAll() {

notifyAll();

}

}

/**

* Task 有其自己的Blocker对象。

*

* @create @author Henry @date 2016-12-21

*

*/

class Task implements Runnable {

static Blocker blocker = new Blocker("Task");

@Override

public void run() {

blocker.waitingCall();

}

}

/**

* Task2 有其自己的Blocker对象。

*

* @create @author Henry @date 2016-12-21

*

*/

class Task2 implements Runnable {

// A separate Blocker object;

static Blocker blocker = new Blocker("Task2");

@Override

public void run() {

blocker.waitingCall();

}

}

/**

* Task和Task2每个都有其自己的Blocker对象,因此每个Task对象都会在Task.blocker上阻塞,而每个Task2都会在

* Taks2.blocker上阻塞。在main()中,java.util.Timer对象呗设置为每4/10秒执行一次run()方法,而这个run()

* 方法将经由“激励”方法交替地在Task.blocker上调用notify()和notifyAll()。

* 从输出中你可以看到,即使存在Task2.blocker上阻塞的Task2对象,也没有任何在Task.blocker上的notify()或

* notifyAll()调用会导致Task2对象被唤醒。于此类似,在main()的结尾,调用了timer的cancel(),即使计时器被撤销了,

* 前5个任务也依然在运行,并仍旧在它们对Task.blocker.waitingCall()的调用中被阻塞。对Task2.blocker.prodAll()

* 的调用所产生的输出不包括任何在Task.blocker中的锁上等待任务。

* 如果你浏览Blocker中的prod()和prodAll(),就会发现这是有意义的。这些方法是synchronized的,这意味着它们将获取自身

* 的锁,因此当它们调用notify()或notifyAll()时,只在这个锁上调用是符合逻辑的---因此,将只唤醒在等待这个特定锁的任务。

* Blocker.waitingCall()非常简单,以至于在本例中,你只需声明for(;;)而不是while(!Thread.interrupted())就可以到达

* 相同的效果,因为在本例中,由于异常而离开循环和通过检查interrupted()标志离开循环时没有任何区别的---在两种情况下都要

* 执行相同的代码。但是事实上,这个示例选择检查interrupted(),因为存在着两种离开循环的方式。如果在以后的某个时刻,

* 你决定要循环中添加更多的代码,那么如果没有覆盖从这个循环中退出的这两条路径,就会产生引入错误的风险。

*

* @create @author Henry @date 2016-12-21

*

*/

public class NotifyVsNotifyAll {

public static void main(String[] args) throws Exception {

ExecutorService exec = Executors.newCachedThreadPool();

for (int i = 0; i < 5; i++)

exec.execute(new Task());

exec.execute(new Task2());

Timer timer = new Timer();

timer.scheduleAtFixedRate(new TimerTask() {

boolean prod = true;

@Override

public void run() {

if (prod) {

System.out.println("\nnotify()");

Task.blocker.prod();

prod = false;

} else {

System.out.println("\nnotifyAll()");

Task.blocker.prodAll();

prod = true;

}

}

}, 400, 400);// Run every .4 second

TimeUnit.SECONDS.sleep(5);

timer.cancel();

System.out.println("\n Timer canceled");

TimeUnit.MILLISECONDS.sleep(500);

System.out.println("Task2.blocker.prodAll()");

Task2.blocker.prodAll();

TimeUnit.MILLISECONDS.sleep(500);

System.out.println("\n Shutting down");

exec.shutdownNow();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值