Java使用wait和notify实现线程同步

本文介绍Java中使用wait和notify方法实现线程间的同步控制。详细解释了wait、notify及notifyAll的功能及其应用场景,并通过示例代码展示了如何在多线程环境中进行线程间通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 * Java使用wait和notify实现线程同步
 * wait、notify、notifyAll是Object对象的属性,并不属于线程。函数解释

 * wait:使持有该对象的线程把该对象的控制权交出去,然后处于等待状态(注:当调用wait的时候会释放锁并处于等待的状态)
 * notify:通知某个正在等待这个对象的控制权的线程可以继续运行(当前线程先获取锁,使自己的程序开始执行,完成任务后通过notify同样去释放锁,并唤醒正在等待的线程)
 * notifyAll:会通知所有等待这个对象控制权的线程继续运行(和上面一样,只不过是唤醒所有等待的线程继续执行, 如果有多个等待线程,必须执行notifyAll,否则只会有一个waiter收到通知线程继续)
 * 通过wait和notify可以做线程之间的通信,当Notifyer线程处理完毕通知Waiter线程执行, 可以相互通知.

看如下示例代码

package com.hulk.sync;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 使用wait和notify实现线程同步
 * wait、notify以及notifyAll
 * wait、notify、notifyAll是Object对象的属性,并不属于线程。我们先解释这三个的一个很重要的概念

 * wait:使持有该对象的线程把该对象的控制权交出去,然后处于等待状态(注:当调用wait的时候会释放锁并处于等待的状态)
 * notify:通知某个正在等待这个对象的控制权的线程可以继续运行(当前线程先获取锁,使自己的程序开始执行,完成任务后通过notify同样去释放锁,并唤醒正在等待的线程)
 * notifyAll:会通知所有等待这个对象控制权的线程继续运行(和上面一样,只不过是唤醒所有等待的线程继续执行, 如果有多个等待线程,必须执行notifyAll,否则只会有一个waiter收到通知线程继续)
 * 通过wait和notify可以做线程之间的通信,当Notifyer线程处理完毕通知Waiter线程执行, 可以相互通知.
 * @author hulk
 *
 */
public class WaitNotifyTest {

	int count = 0;
	//Object mLock = new Object();
	//mLock可以使用this,效果一样(前提是:wait()/notify()和synchronized()中的对象必须是同一个对象)
	Object mLock = this;
	
	/**
	 * 等待
	 * @throws InterruptedException
	 */
	public void doWait() throws InterruptedException {
		System.out.println(Thread.currentThread() + ">access doWait...");
		synchronized (mLock) {
			System.out.println(Thread.currentThread() + ">doWait: 等待");
			//当前线程等待状态,释放mLock所资源,其他线程的可以进入notifyer中的synchronized代码块
			//如果不执行wait就会知道这个代码块执行完毕才能执行其他线程的synchronized代码块
			mLock.wait();
			//继续执行waiter的逻辑极端
			System.out.println(Thread.currentThread() + ">doWait: go on sum count.");
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread() + "-doWait: " + i);
				TimeUnit.SECONDS.sleep(1);
				count += i;
			}
			System.out.println(Thread.currentThread() + ">doWait: count is " + this.count);
		}
	}

	/**
	 * 通知
	 * @throws InterruptedException
	 */
	public void doNotify() throws InterruptedException {
		System.out.println(Thread.currentThread() + ">access doNotify...");
		synchronized (mLock) {
			TimeUnit.SECONDS.sleep(1);
			System.out.println(Thread.currentThread() + ">doNotify: 准备唤醒");
			//用一个循环,模拟完成一些任务
			for (int i = 0; i < 5; i++) {
				System.out.println(Thread.currentThread() + "-doNotify:" + i);
				TimeUnit.MILLISECONDS.sleep(500);
				count += i;
			}
			System.out.println("doNotify: ### notify count is " + count);
			//通知Waiter任务已经完成,其他Waiter可以继续执行了.
			//mLock.notify();
			//如果有多个等待线程,必须执行notifyAll,否则只会有一个waiter收到通知线程继续
			mLock.notifyAll();
		}
	}

	/**
	 * 等待线程
	 * @author hulk
	 *
	 */
	public static class Waiter implements Runnable {
		private WaitNotifyTest test;

		public Waiter(WaitNotifyTest test) {
			this.test = test;
		}

		public void run() {
			try {
				System.out.println(Thread.currentThread() + ">Waiter.run...");
				test.doWait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 等待线程2
	 * @author hulk
	 *
	 */
	public static class Waiter2 implements Runnable {
		private WaitNotifyTest test;

		public Waiter2(WaitNotifyTest test) {
			this.test = test;
		}

		public void run() {
			try {
				System.out.println(Thread.currentThread() + ">Waiter2.run...");
				test.doWait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 通知线程
	 * @author hulk
	 *
	 */
	public static class Notifyer implements Runnable {
		private WaitNotifyTest test;

		public Notifyer(WaitNotifyTest test) {
			this.test = test;
		}

		public void run() {
			try {
				System.out.println(Thread.currentThread() + ">Notifyer.run...");
				test.doNotify();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		WaitNotifyTest test = new WaitNotifyTest();
		ExecutorService executorService = Executors.newCachedThreadPool();
		executorService.execute(new Waiter(test));
		//如果有多个等待线程,必须执行notifyAll,否则只会有一个waiter收到通知线程继续
		executorService.execute(new Waiter2(test));
		executorService.execute(new Notifyer(test));
		executorService.shutdown();
	}
}

异常代码执行结果:

Thread[pool-1-thread-1,5,main]>Waiter.run...
Thread[pool-1-thread-2,5,main]>Waiter2.run...
Thread[pool-1-thread-1,5,main]>access doWait...
Thread[pool-1-thread-2,5,main]>access doWait...
Thread[pool-1-thread-1,5,main]>doWait: 等待
Thread[pool-1-thread-2,5,main]>doWait: 等待
Thread[pool-1-thread-3,5,main]>Notifyer.run...
Thread[pool-1-thread-3,5,main]>access doNotify...
Thread[pool-1-thread-3,5,main]>doNotify: 准备唤醒
Thread[pool-1-thread-3,5,main]-doNotify:0
Thread[pool-1-thread-3,5,main]-doNotify:1
Thread[pool-1-thread-3,5,main]-doNotify:2
Thread[pool-1-thread-3,5,main]-doNotify:3
Thread[pool-1-thread-3,5,main]-doNotify:4
doNotify: ### notify count is 10
Thread[pool-1-thread-2,5,main]>doWait: go on sum count.
Thread[pool-1-thread-2,5,main]-doWait: 0
Thread[pool-1-thread-2,5,main]-doWait: 1
Thread[pool-1-thread-2,5,main]-doWait: 2
Thread[pool-1-thread-2,5,main]-doWait: 3
Thread[pool-1-thread-2,5,main]-doWait: 4
Thread[pool-1-thread-2,5,main]>doWait: count is 20
Thread[pool-1-thread-1,5,main]>doWait: go on sum count.
Thread[pool-1-thread-1,5,main]-doWait: 0
Thread[pool-1-thread-1,5,main]-doWait: 1
Thread[pool-1-thread-1,5,main]-doWait: 2
Thread[pool-1-thread-1,5,main]-doWait: 3
Thread[pool-1-thread-1,5,main]-doWait: 4
Thread[pool-1-thread-1,5,main]>doWait: count is 30

补充一点: wait和sleep相同点和区别:

相同点: 都可以实现当前线程的逻辑暂停,等待释放

区别: 

wait期间所示释放的,其他线程的synchronized代码块可以正常执行,需要等待notify或者notifyAll才能往下执行;

而sleep需要传入睡眠时间,到时间自动释放. sleep期间会一直持有锁, 其他线程无法进入synchronized代码块.

参考: https://blog.youkuaiyun.com/Jin_Kwok/article/details/82423726

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值