一.模型定义
1.生产者持续生产,直到缓冲区满,阻塞;2.缓冲区不满后,继续生产消费者持续消费,直到缓冲区空,阻塞;3.缓冲区不空后,继续消费生产者可以有多个,消费者也可以有多个
二.几种写法
1.常规写法:
/**
* @author Seven 消费者线程 可能有多个消费者
*
*/
public class Consumer extends Thread{
Repo repo;
public Consumer(Repo repo) {
super();
this.repo = repo;
}
@Override
public void run() {
super.run();
while(true) {
repo.remove();
try {
Thread.sleep(5000); //凸显生产线程超过额定数量时阻塞
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* @author Seven 生产者线程
*
*/
public class Producer extends Thread{
Repo repo;
public Producer(Repo repo) {
super();
this.repo = repo;
}
@Override
public void run() {
super.run();
while(true) {
repo.add();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* @author Seven 仓库类
*
*/
public class Repo {
int capacity = 10; // 仓库最大容量
List<Integer> repsList = new ArrayList<Integer>(); // 共享数据区
/**
* 同步方法,向共享数据区添加数据,如果当前数据区等于仓库最大容量, 需要让生产线程等待执行
*
*/
public synchronized void add() {
String name = Thread.currentThread().getName();
if (repsList.size() == 10) {
// 最大容量,等待
try {
System.out.println(name + "添加货物失败" + ",已经超过仓库最大容量了,线程阻塞中,需要等待添加。。。。。");
wait();
System.out.println("线程等待后执行》》》》》》》》》》》");
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
repsList.add(1);
System.out.println(name + "添加货物成功");
System.out.println("只要有货物,生产者就唤醒消费线程获取货物《《《");
notifyAll();// 唤醒在此对象监视器上等待的线程
}
}
/**
* 同步方法,移除共享数据区第一条数据,如果没有数据,则让其线程等待
*/
public synchronized void remove() {
String name = Thread.currentThread().getName();
if (repsList.size() == 0) {
try {
notifyAll();
System.out.println(name + "消费货物失败" + ",仓库已经没有货物了,需要生产者生产货物。。。");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
repsList.remove(0);
System.out.println(name + "消费货物成功");
}
}
}
package com.ts.consumer;
/**
* @author Seven 测试类
*
*/
public class TsMain {
public static void main(String[] args) {
Repo repo=new Repo();
Producer p=new Producer(repo);
p.setName("生产者线程");
Consumer c1=new Consumer(repo);
Consumer c2=new Consumer(repo);
c1.setName("小明消费者");
p.start();
c1.start();
}
}
输出日志:
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
小明消费者消费货物成功
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物成功
只要有货物,生产者就唤醒消费线程获取货物《《《
生产者线程添加货物失败,已经超过仓库最大容量了,线程阻塞中,需要等待添加。。。。。
2.用阻塞队列实现
生产者:
public class Producer extends Thread{
public Producer(BlockingQueue bq) {
super();
this.bq = bq;
}
BlockingQueue bq;
@Override
public void run() {
super.run();
while(true) {
try {
System.out.println("生产数据");
bq.put(1);//put()方法:类似于我们上面的生产者线程,容量达到最大时,自动阻塞。
Thread.sleep(300);
} catch (InterruptedException e) {
System.out.println("生产数据异常");
e.printStackTrace();
}
}
}
}
消费者:
public class Consumer extends Thread{
BlockingQueue bq;
public Consumer(BlockingQueue bq) {
super();
this.bq = bq;
}
@Override
public void run() {
super.run();
while(true) {
try {
System.out.println(getName()+"取出"+bq.take());//take()方法:类似于我们上面的消费者线程,容量为0时,自动阻塞。
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println("取出异常");
e.printStackTrace();
}
}
}
}
测试代码
public class TsMain {
public static void main(String[] args) {
BlockingQueue bq=new LinkedBlockingQueue(10);
Consumer c=new Consumer(bq);
c.setName("c1");
Producer p=new Producer(bq);
Consumer c2=new Consumer(bq);
c2.setName("c2");
c.start();
p.start();
c2.start();
}
}
测试打印
生产数据
c1取出1
生产数据
c2取出1
生产数据
生产数据
c1取出1
生产数据
c2取出1
生产数据
生产数据
c1取出1
生产数据
c2取出1
生产数据
生产数据
c1取出1
生产数据
c2取出1
生产数据
生产数据
生产数据
c1取出1
生产数据
c2取出1
生产数据
生产数据