线程间通信,生产者消费者问题!

本文通过Java线程间通信实现生产者与消费者问题,介绍如何使用共享对象、wait与notify方法实现线程间的同步和通信。

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

线程之间的通信简介:
一般而言,在一个应用程序中(即进程),一个线程往往不是孤立存在的,常常需要和其它线程通信,以执行特定的任务。如主线程和次线程,次线程与次线程,工作线程和用户界面线程等。这样,线程与线程间必定有一个信息传递的渠道。这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的。
线程通信的目标是使线程间能够互相发送信号。另一方面,线程通信使线程能够等待其他线程的信号。
例如,线程B可以等待线程A的一个信号,这个信号会通知线程B数据已经准备好了,典型的例子就是生产者消费者问题,生产者生产了一定量的产品,消费者这边才拥有商品出售。本文将通过JAVA线程间通信来实现生产者与消费者问题,在此之前我们需要了解一下几个知识点:

1、通过共享对象通信(产品)

2、忙等待

3、wait(),notify()和notifyAll()

4、多线程等待相同信号

1.线程间通信的共享对象(Product)

Product类是生产者与消费者的共享类,是实现他们之间数据的共享对象。生产者生产Product,消费者消费Product,所以在Product类中,分别有一个make和一个sale方法。注意,在这两个方法中,都使用了synchronized关键字,实现线程安全机制。在每个方法中,还用到了wait和notify方法, Obj.wait(),与Obj.notify()必须要与synchronized(Obj)一起使用,也就是wait,与notify是针对已经获取了Obj锁进行操作,从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。从功能上来说wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。相应的notify()就是对对象锁的唤醒操作。但有一点需要注意的是notify()调用后,并不是马上就释放对象锁的,而是在相应的synchronized(){}语句块执行结束,自动释放锁后,JVM会在wait()对象锁的线程中随机选取一线程,赋予其对象锁,唤醒线程,继续执行。
具体代码如下:

<span style="font-size:18px;">import java.util.ArrayList;
import java.util.List;

public class Product {
	private String name;
	private int count;
	public static List<Product> list = new ArrayList<Product>();

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getCount() {
		return list.size();
	}

	public void setCount(int count) {
		this.count = count;
	}

	public static List<Product> getList() {
		return list;
	}

	public static void setList(List<Product> list) {
		Product.list = list;
	}

	// /生产方法
	public synchronized void make(Product p) {
		if (getCount() > 9) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			this.notifyAll();
			list.add(p);
		}
	}

	// /消费
	public synchronized void sale() {
		if (getCount() < 1) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			this.notifyAll();
			list.remove(0);
		}

	}
}
</span>

2.生产者类,生产者类实现了Runnable接口,所以是一个线程类。源码如下:

<span style="font-size:18px;">public class Maker implements Runnable {
	Product product = new Product();
	public Maker(Product product) {
		this.product = product;
	}
	public void run() {
		while (true) {
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			Product p = new Product();
			p.setName("aaa");
			product.make(p);
			System.out.println("生产:当前剩余产品-->" + product.getCount());
		}

	}

}
</span>

3.消费者类,消费者类也实现了Runnable接口。

<span style="font-size:18px;">public class Saler implements Runnable {
	
	Product product = new Product();
	public Saler(Product product) {
		this.product = product;
	}
	public void run() {
		while (true) {
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			product.sale();
			System.out.println("消费:当前剩余产品-->" + product.getCount());
		}
	}
}
</span>


4.测试代码如下,在测试代码中,分别创建了四个生产者线程和两个消费者线程。
<span style="font-size:18px;">public class Test {
	public static void main(String[] args) {
		Product product = new Product();
		Maker maker = new Maker(product);
		Saler saler = new Saler(product);
		Thread m1 = new Thread(maker);
		Thread m2 = new Thread(maker);
		Thread m3 = new Thread(maker);
		Thread m4 = new Thread(maker);
		Thread s1 = new Thread(saler);
		Thread s2 = new Thread(saler);
		m1.start();
		m2.start();
		m3.start();
		m4.start();
		s1.start();
		s2.start();
	}
}
</span>

5.运行结果如果下,运行结果中我们可以看到,生产者生产商品的数量,不会超过10个,当商品数量超过10个的时候,生产者就会停止生产,而是等待消费者消费了一定量的商品,才会继续生产。同样,当剩余商品的数量小于0时,消费者也不会继续消费。这就实现了生产者与消费者间的线程通信,两者共享一个数据对象。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值