【我的Java笔记】多线程_等待唤醒机制(生产消费者模式)

等待唤醒机制


生产消费者模式:

1.机制理解:
生产者线程生产数据,如果本身就有数据,需要等待消费者线程输出数据,利用锁对象中的notify()唤醒(通知)消费者线程来输出数据

消费者线程输出数据,那么如果本身没有数据了,需要等待生产者线程产生数据,通知生产者线程生产数据.


2.模式图解




注:在多线程环境下完成此模式各线程应针对同一对象进行才操作





等待唤醒机制

1.目的:等待唤醒机制用于解决线程间通信的问题


2.方法

(1)public final voidwait()告诉当前线程放弃执行权,并放弃监视器(锁)并进入阻塞状态,直到其他线程持有获得执行权,并持有了相同的监视器(锁)并调用notify为止。

注:线程等待,阻塞式方法,调用就会立即释放锁

(2)public final voidnotify()唤醒持有同一个监视器(锁)中调用wait的第一个线程,例如,餐馆有空位置后,等候就餐最久的顾客最先入座。

注:被唤醒的线程是进入了可运行状态。等待cpu执行权。

(3)public final void notifyAll():唤醒持有同一监视器中调用wait的所有的线程。


3.注:调用wait和notify方法需要注意的细节
(1)wait方法与notify方法必须要由同一个锁对象调用(对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程

(2)wait方法与notify方法是属于Object类的方法的(锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的

(3)wait方法与notify方法必须要在同步代码块或者是同步函数中使用(必须要通过锁对象调用这两个方法


4.waite和sleep方法的区别:
(1)相同点:
线程调用wait()或者是sleep()方法都会进入临时阻塞状态,会释放cpu的执行权。并且调用时都需要处理 InterruptedException异常(中断异常)

(2)不同点:
wait(): 释放资源,释放锁。是Object的方法。
sleep():释放资源,不释放锁。是Thread的静态方法



问题:wait(),notify(),notifyAll 方法为什么都定义到Object类而不是Thread类中?

答:使用同步方法解决线程安全问题,wait()和notify() 方法可以释放锁,而Object类可以代表任意对象









例:

// 测试类
public class Test {

	public static void main(String[] args) {

		// 创建产品类对象
		Product product = new Product();

		// 创建资源对象
		Set set = new Set(product);
		Get get = new Get(product);

		// 创建线程类对象
		Thread t1 = new Thread(set);
		Thread t2 = new Thread(get);

		// 启动线程
		t1.start();
		t2.start();

	}
}

// 产品类
class Product {
	String name;
	String number;
	boolean flag;

}

// 生产者线程
class Set implements Runnable {

	private Product product;

	public Set(Product product) {
		this.product = product;
	}

	private int i = 0;

	@Override
	public void run() {

		while (true) {

			synchronized (product) {
				// 进行判断有没有数据
				if (product.flag) {
					try {
						product.wait(); // 处于等待状态,并立即释放锁
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				// 产生数据
				if (i % 2 == 0) {

					product.name = "产品1";
					product.number = "001";
				} else {

					product.name = "产品2";
					product.number = "002";
				}

				i++;

				// 此时有数据了,修改标记
				product.flag = true;
				// 唤醒消费者线程
				product.notify();
			}
		}
	}

}

// 消费者线程
class Get implements Runnable {

	private Product product;

	public Get(Product product) {
		this.product = product;
	}

	@Override
	public void run() {
		while (true) {

			synchronized (product) {
				// 判断有没有数据
				if (!product.flag) {
					try {
						product.wait(); // 线程等待,并立即释放锁
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}

				// 消费数据
				System.out.println(product.name + "---" + product.number);

				// 消费完毕,修改标记
				product.flag = false;
				// 唤醒生产者线程
				product.notify();
			}
		}
	}

}














例2:将产品类中的成员变量私有化,使用同步方法

// 测试类
public class Test {

	public static void main(String[] args) {
		Product product = new Product();
		
		Set set = new Set(product);
		Get get = new Get(product);
		
		Thread t1 = new Thread(set);
		Thread t2 = new Thread(get);
		
		t1.start();
		t2.start();
	}
}

// 产品类
public class Product {

	private String name;
	private String number;
	private boolean flag;
	private int i;

	public synchronized void set() {
		// 判断有没有数据
		if (this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		// 生产数据
		if (i % 2 == 0) {
			this.name = "产品1";
			this.number = "001";
		} else {
			this.name = "产品2";
			this.number = "002";
		}
		
		i++;

		// 修改标记
		this.flag = true;
		// 唤醒
		this.notify();

	}

	public synchronized void get() {

		// 判断有没有数据
		if (!this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		// 消费数据
		System.out.println(this.name + ":" + this.number);

		// 修改标记
		this.flag = false;
		// 唤醒
		this.notify();
	}
}

// 生产者线程
public class Set implements Runnable {
	
	private Product product;
	public Set(Product product) {
		this.product = product;
	}
	@Override
	public void run() {
		while(true) {
			product.set();
		}
		
	}

}


// 消费者线程
public class Get implements Runnable {

	private Product product;
	public Get(Product product) {
		this.product = product;
	}
	@Override
	public void run() {
		while(true) {
			product.get();
		}
		
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值