多线程-线程间通信

wait & notify

wait

wait() 方法的作用是使当前执行的线程进入等待,代码执行到 wait 一行进入等待;当线程被唤醒时从 wait 下一行开始执行。

wait() 方法需要在 synchronized 代码块中调用,否则会报错。

wait() 方法会释放锁,其它线程可以竞争获得锁

wait() 方法有一个带时间参数的,当时间到了可以自动唤醒而不需要notify

notify

notify() 方法的作用是用来通知其它在等待同一把锁的线程,当使用 notify() 方法时,会随机唤醒多个等待线程的其中一个,进行等待获取该锁。

notify() 方法需要在 synchronized 代码块中调用,否则会报错。

notify() 方法不会立马释放锁,(wait 是马上释放锁的),需要等整个代码执行完毕,才会释放锁,被通知的线程也不能马上获取锁,需等 notify 的方法执行完之后,释放了锁,被通知的锁才能获取锁。

notifyAll() 通知所有等待同一把锁的全部线程结束等待,进入可运行状态,全部线程等待方法释放锁然后一起竞争这把锁。

看个例子

public class Tongxin {
	
	public static Object lock = new Object();

	public static void main(String[] args) {
		Tongxin tx = new Tongxin();
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					synchronized(lock) {
						System.out.println(Thread.currentThread().getName() + "调用wait前" + new Date());
						lock.wait();
						System.out.println(Thread.currentThread().getName() + "调用wait后" + new Date());
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName() + "执行最后的操作" + new Date());
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized(lock){
					System.out.println(Thread.currentThread().getName() + "调用notify前" + new Date());
					lock.notify();
					System.out.println(Thread.currentThread().getName() + "调用notify后" + new Date());
					try {
						Thread.sleep(3000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "执行最后的操作" + new Date());
				}
				
			}
		}).start();
	}
}

---运行结果
Thread-0调用wait前Sun Jun 09 12:11:25 CST 2019
Thread-1调用notify前Sun Jun 09 12:11:25 CST 2019
Thread-1调用notify后Sun Jun 09 12:11:25 CST 2019
Thread-1执行最后的操作Sun Jun 09 12:11:28 CST 2019
Thread-0调用wait后Sun Jun 09 12:11:28 CST 2019
Thread-0执行最后的操作Sun Jun 09 12:11:28 CST 2019

可以看到 线程1在调用 notify 之后并没有马上释放掉锁,而是执行完才释放线程0 才能获得锁。

刚才发生了一个小插曲,很纳闷 notify 还没执行完,wait 线程已经获得锁并执行了。

sleep & wait

都会进入等待,但是 sleep 是不会释放锁的,而 wait 会释放锁。

后来才发现,Thread.sleep(3000) 放到 synchronized 块外面去了,锁已经释放掉了,所以才会发生上面的现象。

上面有提到,wait 方法和 notify 方法是需要结合 synchronized 来使用的,如果没有 synchronized 是会报错的。因为需要先获取到对象锁,然后在使用该锁来调用 wait 和 notify。

使用 Lock 对象实现线程间通信

wait 和 notify 是属于 Object 这个超类的方法,所以任何对象都能调用。

Lock 中有个实现类叫 ReentranLock,在 ReentranLock 中可以借用 Condition 对象实现线程间通信。

Condition 是一个接口,await 方法相当于 Object 中的 wait;signal 方法相当于 Object 中的 notify;signalAll 相当于 Object 中的 notifyAll。

例子

public class Tongxin2 {
	
	public static Lock reentranLock = new ReentrantLock();
	public static Condition condition = reentranLock.newCondition();

	public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				reentranLock.lock();
				try {
						System.out.println(Thread.currentThread().getName() + "调用wait前" + new Date());
						condition.await();
						System.out.println(Thread.currentThread().getName() + "调用wait后" + new Date());
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					reentranLock.unlock();
				}
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					reentranLock.lock();
					System.out.println(Thread.currentThread().getName() + "调用notify前" + new Date());
					condition.signal();
					System.out.println(Thread.currentThread().getName() + "调用notify后" + new Date());
					Thread.sleep(3000);
					System.out.println(Thread.currentThread().getName() + "执行最后的操作" + new Date());
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					reentranLock.unlock();
				}
			}
		}).start();
	}
}

--- 运行结果
Thread-0调用wait前Sun Jun 09 15:20:26 CST 2019
Thread-1调用notify前Sun Jun 09 15:20:26 CST 2019
Thread-1调用notify后Sun Jun 09 15:20:26 CST 2019
Thread-1执行最后的操作Sun Jun 09 15:20:29 CST 2019
Thread-0调用wait后Sun Jun 09 15:20:29 CST 2019

可以看到,用法还是很简单,reentranLock.lock() 获得锁,reentranLock.unlock() 释放锁。

区别

就线程间通信而言,Object 中的 wait notify 和 Condition 中的 await signal 没有多大区别。

只是前者是结合 synchronized 来使用,后者是结合 Lock 来使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值