生产者消费者问题是一个典型的线程同步问题。
主要有如下实现方式:
- wait() notifyAll()
class Queue { //共享队列的目的用于保存生产者生产和消费者消费的共享数据
int value = 0;
boolean isEmpty = true;
public synchronized void put(int v)
{
if (!isEmpty)
{
try {
System.out.println("生产者等待");
wait();
} catch(Exception e) {
e.printStackTrace();
}
}
value+=v;
isEmpty = false;
System.out.println("生产者共生产数量:"+v);
notify();
}
public synchronized int get()
{
if(isEmpty)
{
try {
System.out.println("消费者等待");
wait();
}
catch (Exception e)
{
e.printStackTrace();
}
}
value--;
if (value < 1)
{
isEmpty = true;
}
System.out.println("消费者消费一个,剩余:"+value);
notify();
return value;
}
}
//Producer.java文件
class Producer extends Thread {
Queue q;
Producer(Queue q)
{
this.q = q;
}
public void run()
{
for (int i = 1;i < 5; i++)
{
q.put(i);
}
}
}
class Consumer extends Thread {
Queue q;
Consumer(Queue q)
{
this.q = q;
}
public void run()
{
while(true)
{
q.get();
}
}
}
//Test.java文件
public class <span style="line-height: 25.2000007629395px; font-family: Tahoma, Helvetica, Arial, 宋体, sans-serif;">Test</span><span style="line-height: 25.2000007629395px; font-family: Tahoma, Helvetica, Arial, 宋体, sans-serif;">{</span>
public static void main(String[] args)
{
Queue q = new Queue();
Producer p = new Producer(q);
Consumer c = new Consumer(q);
c.start();
p.start();
}
}
class Queue { //共享队列的目的用于保存生产者生产和消费者消费的共享数据
int value = 0;
boolean isEmpty = true;
public synchronized void put(int v)
{
if (!isEmpty)
{
try {
System.out.println("生产者等待");
wait();
} catch(Exception e) {
e.printStackTrace();
}
}
value+=v;
isEmpty = false;
System.out.println("生产者共生产数量:"+v);
notify();
}
public synchronized int get()
{
if(isEmpty)
{
try {
System.out.println("消费者等待");
wait();
}
catch (Exception e)
{
e.printStackTrace();
}
}
value--;
if (value < 1)
{
isEmpty = true;
}
System.out.println("消费者消费一个,剩余:"+value);
notify();
return value;
}
}
//Producer.java文件
class Producer extends Thread {
Queue q;
Producer(Queue q)
{
this.q = q;
}
public void run()
{
for (int i = 1;i < 5; i++)
{
q.put(i);
}
}
}
class Consumer extends Thread {
Queue q;
Consumer(Queue q)
{
this.q = q;
}
public void run()
{
while(true)
{
q.get();
}
}
}
//Test.java文件
public class <span style="line-height: 25.2000007629395px; font-family: Tahoma, Helvetica, Arial, 宋体, sans-serif;">Test</span><span style="line-height: 25.2000007629395px; font-family: Tahoma, Helvetica, Arial, 宋体, sans-serif;">{</span>
public static void main(String[] args)
{
Queue q = new Queue();
Producer p = new Producer(q);
Consumer c = new Consumer(q);
c.start();
p.start();
}
}
- java.util.concurrent.BlockingQueue 实现
BlockingQueue中其中有两个重要的阻塞方法:put()和take()
put():生产商品,当生产商品已经填充满仓库,进入阻塞状
态,唤醒消费者调
用
take()方法
。
take():商品消费完,进入阻塞状态,唤醒生产者。
这两个方法的实现用到了Lock和Condition
package kevin;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* 一个简单的生产者-消费者demo
*
* @author KevinJom
*/
public class BlockingQueueDemo {
public static void main(String[] args) {
new BlockingQueueDemo().go();
}
private void go() {
// 这里简单的说一下BlockingQueue的实现,它基于生产者-消费者模式,其中有两个重要的阻塞方法
// put()和take(),而这两个方法的实现用到了Lock和Condition,具体实现请参考API
BlockingQueue<String> queue = new ArrayBlockingQueue<String>(10);
Thread t1 = new Thread(new Producer(queue, 500, "peak")); // 生产者线程,来,生产一些i
// can
// play吧,并且要比nike生产的快
Thread t2 = new Thread(new Producer(queue, 1000, "nike")); // 第二个生产者线程
Thread t3 = new Thread(new Customer(queue)); // 消费者线程
t1.start();
t2.start();
t3.start();
}
private class Producer implements Runnable {
private BlockingQueue<String> queue;
private int timeout; // 生产一个产品后暂停的时间
private String category; // 仅仅起标记产品作用
public Producer(BlockingQueue<String> queue, int timeout,
String category) {
super();
this.queue = queue;
this.timeout = timeout;
this.category = category;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// put()方法也是一个会阻塞的方法,如果队列已满的时候这个方法会一起阻塞直到
// 队列中重新出现空间为止
queue.put("product " + category);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
TimeUnit.MILLISECONDS.sleep(timeout); // 每生产一个产品就暂停timeout毫秒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class Customer implements Runnable {
private BlockingQueue<String> queue;
public Customer(BlockingQueue<String> queue) {
super();
this.queue = queue;
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("product got:" + queue.take());
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
// 暂停10毫秒,这里主要是为了证明take()是一个阻塞方法,如果 BlockingQueue中
// 没有元素,它会一起阻塞直到队列中有元素为止
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}