(二)线程状态、wait/notify

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(二)线程状态、wait/notify相关的知识,希望对你有一定的参考价值。

参考技术A 在java中线程一共有6种状态。分别为:

sleep不会释放锁(CPU时间片),在存在锁的情况下,线程会一直占有锁,其他线程无法获取。

wait会释放锁,允许其他线程进入同步方法。在调用notify唤醒后会重新去获取锁。

sleep可以在任意地方使用,没有限制。
wait只能在同步方法中使用,依赖于锁。

问题:假如有一个生产者消费者需求:生产者线程对恭喜资源 Integer lock 每次执行加1,达到5以后唤醒消费者,消费者线程每次对Integer lock进行减1,到0时唤醒生产者。在这种情况下,Integer即作为共享资源,又作为锁的对象。那么这种情况会有什么问题呢?

答:问题是无法互相唤醒。
由于消费者是在lock = 0时执行 notify、wait操作,生产者是在lock = 5时执行 notidy、wait操作,因此两个lock其实不是同一个对象,无法执行唤醒。

Synchorized锁

wait/notify 是基于synchorized实现的,await/signal是基于Lock实现的(LookSupport),JUC中提供了Condition类await/signal来代替wait/notify,而Condition底层就是基于park/unpark做的线程通讯。不仅是Condition,AQS中也使用了park/unpark,可以理解为await/signal是park/unpark的外层封装。

wait/notify无法控制唤醒谁,随机唤醒(没有分组的概念)
await/signal可以,await/signal支持多个condition消费者一组,生产者一组,这样在多生产者消费者时可以确保唤醒的一定是分组内的。

答:没有锁的情况是不可以使用的。
可以试想,什么情况下才需要用到等待/唤醒场景呢?
以吃饭举例,到饭店吃饭,点完餐以后自己就进入等待状态(等着吃饭),需要等待服务员唤醒(餐好了通知),此类场景我们就需要用到等待、唤醒。
那么此时需要考虑,如果吃饭的人多了,那么我们怎么知道“餐好了”是谁的餐好了?服务员又怎么知道“餐好了我该叫哪位顾客”?现实场景中我们都是有座位号,或者取餐号,那么这个座位号、取餐号就是我们的锁,我获取到这把锁(其他顾客无法再获取),那么我与我点的餐之间就有了一个关联关系。服务员就可以通过这把锁来对我进行唤醒(1号的餐好了~)。

并发编程基础之wait以及notify的用法

一:概念

线程通信中经常用到wait和notify,顾名思义,wait即让当前线程处于等待状态,notify通知锁对象

上的另一个线程被唤醒,这里的唤醒是指可以去争夺锁资源,nofityAll是唤醒该对象上面所有处于

wait状态的线程

 

二:示例

线程t2一运行就处于wait等待状态,然后线程t1运行notify,唤醒线程t2

/**
 * 
 */
package com.day2;

/**
 * @author Administrator
 *
 */
public class NotifyWaitThreadDemo {

	private int count;

	public static void main(String[] args) {

		NotifyWaitThreadDemo demo = new NotifyWaitThreadDemo();

		Thread t1 = new Thread("t1") {
			public void run() {
				synchronized (demo) {
					for (int i = 0; i < 100; i++) {
						demo.count = i;
						if (demo.count == 50) {
							System.out.println(Thread.currentThread().getName()+"发出通知");
							demo.notify();
						}
					}
				}

			}
		};

		Thread t2 = new Thread("t2") {
			public void run() {
				while (true) {
					synchronized (demo) {
						System.out.println(Thread.currentThread().getName() + "开始等待");
						try {
							demo.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println(Thread.currentThread().getName() + "跳出等待");
					System.out.println("demo.count" + demo.count);
					break;
				}

			}
		};
		
		t2.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t1.start();
		
	}
}

  

如果还有一个线程t3也处于wait状态,那么t1线程如果想唤醒t1和t3,就需要使用notifyAll

/**
 * 
 */
package com.day2;

/**
 * @author Administrator
 *
 */
public class NotifyWaitThreadDemo {

	private int count;

	public static void main(String[] args) {

		NotifyWaitThreadDemo demo = new NotifyWaitThreadDemo();

		Thread t1 = new Thread("t1") {
			public void run() {
				synchronized (demo) {
					for (int i = 0; i < 100; i++) {
						demo.count = i;
						if (demo.count == 50) {
							System.out.println(Thread.currentThread().getName()+"发出通知");
							//demo.notify();
							demo.notifyAll();
						}
					}
				}

			}
		};

		Thread t2 = new Thread("t2") {
			public void run() {
				while (true) {
					synchronized (demo) {
						System.out.println(Thread.currentThread().getName() + "开始等待");
						try {
							demo.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println(Thread.currentThread().getName() + "跳出等待");
					System.out.println("demo.count" + demo.count);
					break;
				}

			}
		};
		
		Thread t3 = new Thread("t3") {
			public void run() {
				while (true) {
					synchronized (demo) {
						System.out.println(Thread.currentThread().getName() + "开始等待");
						try {
							demo.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					System.out.println(Thread.currentThread().getName() + "跳出等待");
					break;
				}

			}
		};
		t2.start();
		t3.start();
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t1.start();
		
	}
}

  

运行结果:

t2开始等待
t3开始等待
t1发出通知
t3跳出等待
t2跳出等待
demo.count99

  

以上是关于(二)线程状态、wait/notify的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程原理与实战二十一:线程通信wait&notify&join

JAVA多线程suspend,resume和wait,notify的区别

线程的通讯-----wait和notify的使用

Java多线程——wait方法和notify方法的详解

Java多线程系列 基础篇07 wait/notify/sleep/yield/join

线程通讯