文档章节

java基础---->线程 生产者消费者问题

小强斋太
 小强斋太
发布于 2016/11/09 20:07
字数 962
阅读 1
收藏 0

生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,

如果不加以协调可能会出现以下情况:

存储空间已满,而生产者占用着它,消费者等着生产者让出空间从而去除产品,生产者等着消费者消费产品,从而向空间中添加产品。互相等待,从而发生死锁。

存储空间为空,而消费者占用着它,生产者等着消费者让出空间从而添加产品,消费者等着生产者生产产品,从而从空间中去除产品。互相等待,从而发生死锁。

JAVA解决线程模型的三种方式

1、wait()和notify()

import java.util.LinkedList;

public class ProducerConsumer {
    private LinkedList<Object> storeHouse = new LinkedList<Object>();
    private int MAX = 10;

    public ProducerConsumer() {
    }

    public void start() {
        new Producer().start();
        new Comsumer().start();
    }

    class Producer extends Thread {
        public void run() {
            while (true) {
                synchronized (storeHouse) {
                    try {
                        while (storeHouse.size() == MAX) {
                            System.out.println("storeHouse is full , please wait");
                            storeHouse.wait();
                        }
                        Object newOb = new Object();
                        if (storeHouse.add(newOb)) {
                            System.out.println("Producer put a Object to storeHouse");
                            Thread.sleep((long) (Math.random() * 3000));
                            storeHouse.notify();
                        }
                    } catch (InterruptedException ie) {
                        System.out.println("producer is interrupted!");
                    }

                }
            }
        }
    }

    class Comsumer extends Thread {
        public void run() {
            while (true) {
                synchronized (storeHouse) {
                    try {
                        while (storeHouse.size() == 0) {
                            System.out.println("storeHouse is empty , please wait");
                            storeHouse.wait();
                        }
                        storeHouse.removeLast();
                        System.out.println("Comsumer get  a Object from storeHouse");
                        Thread.sleep((long) (Math.random() * 3000));
                        storeHouse.notify();
                    } catch (InterruptedException ie) {
                        System.out.println("Consumer is interrupted");
                    }

                }
            }

        }
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumer pc = new ProducerConsumer();
        pc.start();
    }
}

2、await()和signal(),即线程锁的方式

package sort;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProducerConsumer {
    private LinkedList<Object> myList = new LinkedList<Object>();
    private int MAX = 10;
    private final Lock lock = new ReentrantLock();
    private final Condition full = lock.newCondition();
    private final Condition empty = lock.newCondition();

    public ProducerConsumer() {
    }

    public void start() {
        new Producer().start();
        new Consumer().start();
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumer s2 = new ProducerConsumer();
        s2.start();
    }

    class Producer extends Thread {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (myList.size() == MAX) {
                        System.out.println("warning: it's full!");
                        full.await();
                    }
                    Object o = new Object();
                    if (myList.add(o)) {
                        System.out.println("Producer: " + o);
                        empty.signal();
                    }
                } catch (InterruptedException ie) {
                    System.out.println("producer is interrupted!");
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    class Consumer extends Thread {
        public void run() {
            while (true) {
                lock.lock();
                try {
                    while (myList.size() == 0) {
                        System.out.println("warning: it's empty!");
                        empty.await();
                    }
                    Object o = myList.removeLast();
                    System.out.println("Consumer: " + o);
                    full.signal();
                } catch (InterruptedException ie) {
                    System.out.println("consumer is interrupted!");
                } finally {
                    lock.unlock();
                }
            }
        }
    }

}

3、阻塞队列的方式

import java.util.concurrent.*;

public class ProducerConsumer {
    // 建立一个阻塞队列
    private LinkedBlockingQueue<Object> queue = new LinkedBlockingQueue<Object>(10);

    public ProducerConsumer() {
    }

    public void start() {
        new Producer().start();
        new Consumer().start();
    }

    public static void main(String[] args) throws Exception {
        ProducerConsumer s3 = new ProducerConsumer();
        s3.start();
    }

    class Producer extends Thread {
        public void run() {
            while (true) {
                try {
                    Object o = new Object();
                    // 取出一个对象
                    queue.put(o);
                    System.out.println("Producer: " + o);
                } catch (InterruptedException e) {
                    System.out.println("producer is interrupted!");
                }
                // }
            }
        }
    }

    class Consumer extends Thread {
        public void run() {
            while (true) {
                try {
                    // 取出一个对象
                    Object o = queue.take();
                    System.out.println("Consumer: " + o);
                } catch (InterruptedException e) {
                    System.out.println("producer is interrupted!");
                }
                // }
            }
        }
    }

}

三种方式原理一致,都是对独占空间加锁,阻塞和唤醒线程,第一种方式比较传统,第三种方式最简单,只需存储和取用,线程同步的操作交由LinkedBlockingQueue全权处理。

 

 

wait()和notify()其他例子

产品类

//生产的产品
public class Product {
	private  int productId;

	public Product(int productId) {
		this.productId = productId;
	}

	public int getProductId() {
		return productId;
	}

	public void setProductId(int productId) {
		this.productId = productId;
	}

	@Override
	public String toString() {
		return "product_"+productId;
	}
}

仓库类

import java.util.ArrayList;
import java.util.List;

public class StoreHouse {
	private static final Integer initialSize = 10;
	private List<Product> list = null;

	public StoreHouse() {

		this.list = new ArrayList<Product>(initialSize);

	}

	public synchronized void put(Product product) {
		if (list.size() == StoreHouse.initialSize) {
			try {
				System.out.println("仓库已满,等待消费者消费");
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		list.add(product);
		System.out.println("放入仓库" + product);
		notifyAll();

	}

	public synchronized void get() {
		if (list.size() == 0) {
			try {
				System.out.println("仓库为空,等待生产者生产");
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		Product product = list.get(list.size()-1);
		System.out.println("从仓库取出" + product);
		list.remove(list.size()-1);
		notifyAll();
	}

}

生产者

public class Producer implements Runnable {

	StoreHouse storeHouse = null;

	public Producer(StoreHouse storeHouse) {
		this.storeHouse = storeHouse;
	}

	@Override
	public void run() {
		int i = 0;
		while (true) {

			Product product = new Product(++i);
			storeHouse.put(product);
			 try { 
	                Thread.sleep(1000); 
	            } catch (InterruptedException e) { 
	                return; 
	            } 

		}
	}

}

消费者

public class Consumer implements Runnable {

	StoreHouse storeHouse = null;

	public Consumer(StoreHouse storeHouse) {
		this.storeHouse = storeHouse;
	}

	@Override
	public void run() {
		int i = 0;
		while (true) {
			storeHouse.get();
			 try { 
	                Thread.sleep(1500); 
	            } catch (InterruptedException e) { 
	                return; 
	            } 
		}
	}

}


客户端测试

public class Client {

	public static void main(String[] args) {
		StoreHouse storeHouse = new StoreHouse();

		Runnable producer = new Producer(storeHouse);
		Runnable consumer = new Consumer(storeHouse);
		Thread produceThread = new Thread(producer);
		Thread consumeThread = new Thread(consumer);
		produceThread.start();
		consumeThread.start();
	}

}



 

 

本文转载自:http://www.cnblogs.com/xqzt/archive/2013/01/12/5637115.html

共有 人打赏支持
小强斋太
粉丝 0
博文 181
码字总数 0
作品 0
广州
私信 提问
Java并发基础你需要知道的基础知识

多线程和并发编程是Java里面的核心内容,通常有以下一些概念需要重点掌握。 线程; 锁; 同步器; 并发容器和框架; Java并发工具类; 原子操作类; Executor框架(执行机制); 并发基础概念 ...

异步社区
05/30
0
0
你真的懂wait、notify和notifyAll吗

生产者消费者模型是我们学习多线程知识的一个经典案例,一个典型的生产者消费者模型如下: 这段代码很容易引申出来两个问题:一个是wait()方法外面为什么是while循环而不是if判断,另一个是结...

A_客
06/03
0
0
JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费者、线程池、匿名内部类使用多线程、定时器、面试题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52714313 JAVA基础再回首(二十五)——Lock锁的使用、死锁问题、多线程生产者和消费...

Aduroidpc
2016/10/01
0
0
RabbitMQ 入门指南(Java)

RabbitMQ是一个受欢迎的消息代理,通常用于应用程序之间或者程序的不同组件之间通过消息来进行集成。本文简单介绍了如何使用 RabbitMQ,假定你已经配置好了rabbitmq服务器。 RabbitMQ是用Erl...

oschina
2013/06/21
89.6K
22
ActiveMQ : Async error occurred: java.lang.OutO...

参考--http://activemq.apache.org/javalangoutofmemory.html 对于MQ的内容实用是可管理和可配置的。首先需要判断的是MQ的哪部分系统因内存不足而导致泄漏,是JVM,broker还是消费者、生产者...

hbdrawn
2011/06/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

7个习惯提升python效率

1. 使用本地变量 尽量使用局部变量,避免使用全局变量 2.减少函数调用 (1)当我们判断对象的类别的时候,尽量使用isinstance(),其次使用id(),最不济使用type()   type(num)==type(0) type(...

糖宝lsh
14分钟前
2
0
mongodb使用

【mongodb全库备份:】 #cd /usr/local/mongodb/bin # ./mongodump 则会在当前目录生成一个dump目录,整个库会备份在这个目录下。 【指定数据库备份】 # ./mongodump -h localhost -d Hawkey...

硅谷课堂
18分钟前
1
0
hive count distinct和group by

首先,Hive的group by和count(distinct)都是去除重复的数据,某种程度上来说,两者产生的结果是一样的。 实例代码: select a,count(distinct b) from t group by aselect tt.a,count(tt...

张欢19933
22分钟前
1
0
day180-2018-12-17-英语流利阅读-待学习

“黄马甲”再上巴黎街头,马克龙成为众矢之的 毛西 2018-12-17 1.今日导读 圣诞将至,但此时的法国人都在担心周六的到来,因为巴黎的“黄背心”抗议活动已经连续进行了四周,举国上下人心惶惶...

飞鱼说编程
24分钟前
7
0
Deepin 下安装 Docker

Docker官网上并没有提供关于 Deepin 的 Docker 安装教程,由于 Deepin 是基于 Debian 的,所以可以参照官网 Debian的安装教程安装,但 Deepin 在定制过程中进行了大量修改,所以使用官方教程...

临江仙卜算子
26分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部