专栏首页做不甩锅的后端在java中notify和notifyAll的区别

在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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 多线程基础(九):守护线程、yield、join及线程组

    不经意间都已经在上一篇文章中聊到ReentrantLock了,但是回头一看,关于多线程基础的内容还有很多没涉及2到,而ReentrantLock却是属于...

    冬天里的懒猫
  • 多线程基础(三):synchronized关键字及java内存模型简介

    在前面了解过一些java多线程基础之后,现在,我们用多线程来解决一个实际问题。 假定每个线程可以将一个数字加到100000,现在我们用十个线程,同时相加,看看...

    冬天里的懒猫
  • 多线程基础(八):ReentrantLock的使用及与synchronized的区别

    还记得,前面一篇文章《什么?面试官让我用ArrayList实现一个阻塞队列?》中,描述了一个关于实现两个线程交替打印以及实现阻塞队列的例子,那么今天,我们来看看...

    冬天里的懒猫
  • 史上最全 Java 中各种锁的介绍

    在计算机科学中,锁(lock)或互斥(mutex)是一种同步机制,用于在有许多执行线程的环境中强制对资源的访问限制。锁旨在强制实施互斥排他、并发控制策略。 ...

    java金融
  • Java并发之 volatile & synchronized & ThreadLocal 讲解

    Java 之 volatile & synchronized & ThreadLocal 讲解 在并发编程中,基本上离不开这三个东西,如何实现多线程之间的数据...

    一灰灰blog
  • Java线程(八):锁对象Lock-同步问题更完美的处理方式

            Lock是java.util.concurrent.locks包下的接口,Lock 实现提供了比使用synchronized 方法和语句可获得的...

    高爽
  • ReentrantLock实现原理

    建议和上一篇分享结合着看:深入理解AbstractQueuedSynchronizer

    Java识堂
  • 递归就这么简单

    递归介绍 本来预算此章节是继续写快速排序的,然而编写快速排序往往是递归来写的,并且递归可能不是那么好理解,于是就有了这篇文章。 在上面提到了递归这么一个词,递归...

    Java3y
  • JUC包下的CountDownLatch,CyclicBarrier,Semaphore

    ①.从CountDownLatch的设计来看,可以做汇总的操作,例如计算员工工资,这边启动多个线程同时计算等所有线程执行完毕之后,计算需要发放的总额 final...

    用户1215919
  • React Native 入坑之旅

    要注意,创建时HellowWorld不能有空格,必须指定0.44.3之前的版本。精确到两个小数点,否则运行会出问题。cd到项目根目录,执行npm install...

    Raindew

扫码关注云+社区

领取腾讯云代金券