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

来源:互联网 发布:cf无后坐力软件 编辑:程序博客网 时间:2024/05/29 16:35
线程之间的通信简介:
一般而言,在一个应用程序中(即进程),一个线程往往不是孤立存在的,常常需要和其它线程通信,以执行特定的任务。如主线程和次线程,次线程与次线程,工作线程和用户界面线程等。这样,线程与线程间必定有一个信息传递的渠道。这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的。
线程通信的目标是使线程间能够互相发送信号。另一方面,线程通信使线程能够等待其他线程的信号。
例如,线程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时,消费者也不会继续消费。这就实现了生产者与消费者间的线程通信,两者共享一个数据对象。





0 0
原创粉丝点击