Java多线程之并发协作生产者消费者设计模式
来源:互联网 发布:贾真的淘宝店地址 编辑:程序博客网 时间:2024/05/29 02:21
两个线程一个生产者个一个消费者
需求情景
两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个
涉及问题
同步问题:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用标记或加锁机制
wait() / nofity() 方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。
wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。
notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
代码实现(共三个类和一个main方法的测试类)
/**
* Created by yuandl on 2016-10-11./**
* 资源
*/
public
class
Resource {
/*资源序号*/
private int number = 0; /*资源标记*/
private boolean flag = false; /**
* 生产资源
*/
public synchronized void create() { if (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费;
try {
wait();//让生产线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;//生产一个
System.out.println(Thread.currentThread().getName() + "生产者------------" + number);
flag = true;//将资源标记为已经生产
notify();//唤醒在等待操作资源的线程(队列)
} /**
* 消费资源
*/
public
synchronized
void
destroy() {
if
(!flag) {
try
{
wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() +
"消费者****"
+ number);
flag =
false
;
notify();
}
}
/**
* Created by yuandl on 2016-10-11.
*
/**
* 生产者
*/
public
class
Producer
implements
Runnable {
private
Resource resource;
public
Producer(Resource resource) {
this
.resource = resource;
}
@Override
public
void
run() {
while
(
true
) {
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
resource.create();
}
}
}
/**
* 消费者
*/
public
class
Consumer
implements
Runnable {
private
Resource resource;
public
Consumer(Resource resource) {
this
.resource = resource;
}
@Override
public
void
run() {
while
(
true
) {
try
{
Thread.sleep(
10
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
resource.destroy();
}
}
}
/**
* Created by yuandl on 2016-10-11.
*/
public
class
ProducerConsumerTest {
public
static
void
main(String args[]) {
Resource resource =
new
Resource();
new
Thread(
new
Producer(resource)).start();
//生产者线程
new
Thread(
new
Consumer(resource)).start();
//消费者线程
}
}
Thread-
0
生产者------------
1
Thread-
1
消费者****
1
Thread-
0
生产者------------
2
Thread-
1
消费者****
2
Thread-
0
生产者------------
3
Thread-
1
消费者****
3
Thread-
0
生产者------------
4
Thread-
1
消费者****
4
Thread-
0
生产者------------
5
Thread-
1
消费者****
5
Thread-
0
生产者------------
6
Thread-
1
消费者****
6
Thread-
0
生产者------------
7
Thread-
1
消费者****
7
Thread-
0
生产者------------
8
Thread-
1
消费者****
8
Thread-
0
生产者------------
9
Thread-
1
消费者****
9
Thread-
0
生产者------------
10
Thread-
1
消费者****
10
多个线程,多个生产者和多个消费者的问题
需求情景
四个线程,两个个负责生产,两个个负责消费,生产者生产一个,消费者消费一个
涉及问题
notifyAll()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的所有线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
再次测试代码
/**
* Created by yuandl on 2016-10-11.
*/
public
class
ProducerConsumerTest {
public
static
void
main(String args[]) {
Resource resource =
new
Resource();
new
Thread(
new
Consumer(resource)).start();
//生产者线程
new
Thread(
new
Consumer(resource)).start();
//生产者线程
new
Thread(
new
Producer(resource)).start();
//消费者线程
new
Thread(
new
Producer(resource)).start();
//消费者线程
}
}
Thread-
0
生产者------------
100
Thread-
3
消费者****
100
Thread-
0
生产者------------
101
Thread-
3
消费者****
101
Thread-
2
消费者****
101
Thread-
1
生产者------------
102
Thread-
3
消费者****
102
Thread-
0
生产者------------
103
Thread-
2
消费者****
103
Thread-
1
生产者------------
104
Thread-
3
消费者****
104
Thread-
1
生产者------------
105
Thread-
0
生产者------------
106
Thread-
2
消费者****
106
Thread-
1
生产者------------
107
Thread-
3
消费者****
107
Thread-
0
生产者------------
108
Thread-
2
消费者****
108
Thread-
0
生产者------------
109
Thread-
2
消费者****
109
Thread-
1
生产者------------
110
Thread-
3
消费者****
110
101生产了一次,消费了两次
105生产了,而没有消费
当两个线程同时操作生产者生产或者消费者消费时,如果有生产者或者的两个线程都wait()时,再次notify(),由于其中一个线程已经改变了标记而另外一个线程再次往下直接执行的时候没有判断标记而导致的。
if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。
while判断标记,解决了线程获取执行权后,是否要运行!也就是每次wait()后再notify()时先再次判断标记
代码改进(Resource中的if->while)
/**
* Created by yuandl on 2016-10-11./**
* 资源
*/
public
class
Resource {
/*资源序号*/
private int number = 0; /*资源标记*/
private boolean flag = false; /**
* 生产资源
*/
public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费;
try {
wait();//让生产线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;//生产一个
System.out.println(Thread.currentThread().getName() + "生产者------------" + number);
flag = true;//将资源标记为已经生产
notify();//唤醒在等待操作资源的线程(队列)
} /**
* 消费资源
*/
public
synchronized
void
destroy() {
while
(!flag) {
try
{
wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() +
"消费者****"
+ number);
flag =
false
;
notify();
}
}
打印到某个值比如生产完74,程序运行卡死了,好像锁死了一样。
notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致”死锁”。
notifyAll解决了本方线程一定会唤醒对方线程的问题。
最后代码改进(Resource中的notify()->notifyAll())
/**
* Created by yuandl on 2016-10-11./**
* 资源
*/
public
class
Resource {
/*资源序号*/
private int number = 0; /*资源标记*/
private boolean flag = false; /**
* 生产资源
*/
public synchronized void create() { while (flag) {//先判断标记是否已经生产了,如果已经生产,等待消费;
try {
wait();//让生产线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;//生产一个
System.out.println(Thread.currentThread().getName() + "生产者------------" + number);
flag = true;//将资源标记为已经生产
notifyAll();//唤醒在等待操作资源的线程(队列)
} /**
* 消费资源
*/
public
synchronized
void
destroy() {
while
(!flag) {
try
{
wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() +
"消费者****"
+ number);
flag =
false
;
notifyAll();
}
}
Thread-
0
生产者------------
412
Thread-
2
消费者****
412
Thread-
0
生产者------------
413
Thread-
3
消费者****
413
Thread-
1
生产者------------
414
Thread-
2
消费者****
414
Thread-
1
生产者------------
415
Thread-
2
消费者****
415
Thread-
0
生产者------------
416
Thread-
3
消费者****
416
Thread-
1
生产者------------
417
Thread-
3
消费者****
417
Thread-
0
生产者------------
418
Thread-
2
消费者****
418
Thread-
0
生产者------------
419
Thread-
3
消费者****
419
Thread-
1
生产者------------
420
Thread-
2
消费者****
420
- Java多线程之并发协作生产者消费者设计模式
- Java多线程之并发协作生产者消费者设计模式
- Java多线程之并发协作生产者消费者设计模式
- Java多线程之并发协作生产者消费者设计模式
- Java多线程之并发协作生产者消费者设计模式
- Java多线程Thread-并发协作(生产者消费者设计模式)
- Java多线程之并发协作生产者消费者设计模式JDK1.5.0+升级优化版
- Java多线程-并发协作(生产者消费者模型)
- Java多线程---并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- Java多线程-并发协作(生产者消费者模型)
- eclipse插件开发简介
- 跨进程通信
- jsp url文件判断是否存在
- SWT/JFace中Table相同列多种类型CellEditor以及参照类型编辑器的实现
- SWT实现简易Cron表达式编辑器
- Java多线程之并发协作生产者消费者设计模式
- Tomcat配置多个端口号或多个应用,使得域名后面加不同端口访问
- 操作系统——进程间通信和调度
- 在servlet、filter、Taglib中获取Spring Bean
- Ubuntu16.04开机登陆后直接进入命令行界面
- struts2 迭代标签获取list集合的两种情况
- redis-3.0 主从复制
- 操作系统——存储管理
- JSP —— scope取值page、request、session、application