在java中notify和notifyAll的区别
时间:2022-07-24
本文章向大家介绍在java中notify和notifyAll的区别,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
notify()和notifyAll()以及wait()方法用于线程间的通信。通过调用wait()方法进入WaitSet的线程会一直处于WAITING状态,直到任何其他的线程在同一锁的对象上调用notify()或者notify()方法。 限制的问题是,notify()和notifyAll()方法都是用来向处于WAITING状态的线程发送通知的,那么他们之间有什么区别,或者我们应该在哪使用notify()或者notifyAll方法? 让我们先来看看notify的行文:
class Geek1 extends Thread {
@Override
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "...starts");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...notified");
}
}
}
class Geek2 extends Thread {
Geek1 geeks1;
Geek2(Geek1 geeks1) {
this.geeks1 = geeks1;
}
@Override
public void run() {
synchronized (this.geeks1) {
System.out.println
(Thread.currentThread().getName() + "...starts");
try {
this.geeks1.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println
(Thread.currentThread().getName() + "...notified");
}
}
}
class Geek3 extends Thread {
Geek1 geeks1;
Geek3(Geek1 geeks1) {
this.geeks1 = geeks1;
}
@Override
public void run() {
synchronized (this.geeks1) {
System.out.println
(Thread.currentThread().getName() + "...starts");
this.geeks1.notify();
System.out.println
(Thread.currentThread().getName() + "...notified");
}
}
}
class MainClass {
public static void main(String[] args) throws InterruptedException {
Geek1 geeks1 = new Geek1();
Geek2 geeks2 = new Geek2(geeks1);
Geek3 geeks3 = new Geek3(geeks1);
Thread t1 = new Thread(geeks1, "Thread-1");
Thread t2 = new Thread(geeks2, "Thread-2");
Thread t3 = new Thread(geeks3, "Thread-3");
t1.start();
t2.start();
Thread.sleep(100);
t3.start();
}
}
上述代码执行结果如下:
Thread-1...starts
Thread-2...starts
Thread-3...starts
Thread-3...notified
Thread-1...notified
我们再看看notifyAll的行为:
// Java program to illustrate the
// behavior of notifyAll() method
class Geek1 extends Thread {
public void run()
{
synchronized(this)
{
System.out.println
(Thread.currentThread().getName() + "...starts");
try {
this.wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println
(Thread.currentThread().getName() + "...notified");
}
}
} class Geek2 extends Thread {
Geek1 geeks1;
Geek2(Geek1 geeks1)
{
this.geeks1 = geeks1;
}
public void run()
{
synchronized(this.geeks1)
{
System.out.println
(Thread.currentThread().getName() + "...starts");
try {
this.geeks1.wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println
(Thread.currentThread().getName() + "...notified");
}
}
} class Geek3 extends Thread {
Geek1 geeks1;
Geek3(Geek1 geeks1)
{
this.geeks1 = geeks1;
}
public void run()
{
synchronized(this.geeks1)
{
System.out.println
(Thread.currentThread().getName() + "...starts");
this.geeks1.notifyAll();
System.out.println
(Thread.currentThread().getName() + "...notified");
}
}
} class MainClass {
public static void main(String[] args) throws InterruptedException
{
Geek1 geeks1 = new Geek1();
Geek2 geeks2 = new Geek2(geeks1);
Geek3 geeks3 = new Geek3(geeks1);
Thread t1 = new Thread(geeks1, "Thread-1");
Thread t2 = new Thread(geeks2, "Thread-2");
Thread t3 = new Thread(geeks3, "Thread-3");
t1.start();
t2.start();
Thread.sleep(100);
t3.start();
}
}
执行结果:
Thread-1...starts
Thread-2...starts
Thread-3...starts
Thread-3...notified
Thread-2...notified
Thread-1...notified
- 1.通知线程的数量,我们可以使用notify方法只给一个等待的特定的线程发送通知。而通过notify方法,我们可以给这个等待特定对象的所有线程发送通知。
- 2.由JVM决定如何通知:如果多个线程正在等待通知,并且我们使用了notify方法,那么只有一个线程得到通知,其余的线程必须等待进一步的通知,我们不能期望哪个线程会得到通知,因为这个实现完全取决于JVM。但是当我们使用notifyAll的时候,多个线程得到了通知,但是线程的执行将逐个执行,因为线程中需要获得锁,而且一个对象只有要给锁可用。
- 3.线程的互换性:如果所有等待的线程都是可以互换的,他们唤醒的顺序无关紧要。我们应该使用notify。一个常见的例子就是线程池,再这种情况下,等待线程可能由不同的目的,并且应该能够并发运行,一个示例是对共享资源的维护操作,其中多个线程再访问资源之前等待操作完成。
何时使用notify和notifyAll
- 在互斥锁的情况下,只有一个等待的线程在受到通知之后可以做一些有用的事情,本例提到的获得锁,在这种情况下,你应该使用notify,如果真确实现的话,你也可以在这种情况下使用notifyAll,但是你会不必要地唤醒哪些无论如何都不能做任何事情的线程。
- 在某些情况下,一旦等待结束,所有等待的线程都可以采取有用的操作。例如,一组等待的某个任务完成的线程,一旦任务完成,所有等待的线程都可以继续他们的业务,在这种情况下,你可以使用notifyAll来同时唤醒所有的等待线程。
notify和notifyAll应用
- 对共享资源的维护操作,其中多个线程在访问资源之前等待操作完成,对于这些,我们应该使用notifyAll。
- 假设我们有一个生产者线程和一个消费者线程,生产者生产的每个包应该由消费者消费, 生产者将一些东西放入队列,然后调用notify。
- 我们希望在长进程完成的时候收到通知,你向要一个声音或者屏幕更新,进程执行notifyAll来通知声音程序和屏幕更新。
参考https://stackoverflow.com/questions/37026/java-notify-vs-notifyall-all-over-again
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释