- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java多线程中不同条件下编写生产消费者模型方法介绍由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
简介:
生产者、消费者模型是多线程编程的常见问题,最简单的一个生产者、一个消费者线程模型大多数人都能够写出来,但是一旦条件发生变化,我们就很容易掉进多线程的bug中。这篇文章主要讲解了生产者和消费者的数量,商品缓存位置数量,商品数量等多个条件的不同组合下,写出正确的生产者消费者模型的方法.
欢迎探讨,如有错误敬请指正 。
生产消费者模型 。
生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色,他们通过内存缓冲区进行通信,生产者生产消费者需要的资料,消费者把资料做成产品。生产消费者模式如下图.
定义商品类 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package
demo;
/*定义商品*/
public class goods {
public final string name;
public final int price;
public final int id;
public goods(string name, int price, int id){
this.name = name;
/*类型*/
this.price = price;
/*价格*/
this.id = id;
/*商品序列号*/
}
@override
public
string tostring(){
return
"name: "
+ name +
", price:"
+ price +
", id: "
+ id;
}
}
|
基本要求:
1)生产者不能重复生产一个商品,也就是说不能有两个id相同的商品 。
2)生产者不能覆盖一个商品(当前商品还未被消费,就被下一个新商品覆盖)。也就是说消费商品时,商品的id属性可以不连续,但不能出现缺号的情况 。
3)消费者不能重复消费一个商品 。
1.生产者线程无线生产,消费者线程无限消费的模式 。
1.1使用线程对象,一个生产者线程,一个消费者线程,一个商品存储位置 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
|
package
demo;
import
java.util.random;
/*使用线程对象,一个缓存位置,一个生产者,一个消费者,无限生产商品消费商品*/
public class productercomsumerdemo1 {
/*定义一个商品缓存位置*/
private volatile goods goods;
/*定义一个对象作为锁,不使用goods作为锁是因为生产者每次会产生一个新的对象*/
private object obj = new object();
/*isfull == true 生产者线程休息,消费者线程消费
*isfull == false 消费者线程休息,生产者线程生产*/
private volatile boolean isfull = false;
/*商品的id编号,生产者制造的每个商品的id都不一样,每生产一个id自增1*/
private int id = 1;
/*随机产生一个sleep时间*/
private random rnd = new random();
/*=================定义消费者线程==================*/
public class comsumethread implements runnable{
@override
public void run(){
try{
while(true){
/*获取obj对象的锁, id 和 isfull 的操作都在同步代码块中*/
synchronized(obj){
if(!isfull){
/*wait方法使当前线程阻塞,并释放锁*/
obj.wait();
}
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
/*模拟消费商品*/
system.out.println(goods);
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
isfull = false;
/*唤醒阻塞obj上的生产者线程*/
obj.notify();
}
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
}
}
catch (interruptedexception e){
/*什么都不做*/
}
}
}
/*=================定义生产者线程==================*/
public class productthread implements runnable{
@override
public void run(){
try {
while(true){
synchronized(obj){
if(isfull){
obj.wait();
}
thread.sleep(rnd.nextint(500));
/*如果id为偶数,生产价格为2的产品a
*如果id为奇数,生产价格为1的产品b*/
if(id % 2 == 0){
goods = new goods("a", 2, id);
} else{
goods = new goods("b", 1, id);
}
thread.sleep(rnd.nextint(250));
id++;
isfull = true;
/*唤醒阻塞的消费者线程*/
obj.notify();
}
}
}
catch (interruptedexception e) {
/*什么都不做*/
}
}
}
public
static
void
main(string[] args)
throws
interruptedexception{
productercomsumerdemo1 pcd =
new
productercomsumerdemo1();
runnable c = pcd.
new
comsumethread();
runnable p = pcd.
new
productthread();
new
thread(p).start();
new
thread(c).start();
}
}
|
运行结果 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
name: b, price:
1
, id:
1
name: a, price:
2
, id:
2
name: b, price:
1
, id:
3
name: a, price:
2
, id:
4
name: b, price:
1
, id:
5
name: a, price:
2
, id:
6
name: b, price:
1
, id:
7
name: a, price:
2
, id:
8
name: b, price:
1
, id:
9
name: a, price:
2
, id:
10
name: b, price:
1
, id:
11
name: a, price:
2
, id:
12
name: b, price:
1
, id:
13
……
|
从结果看出,商品类型交替生产,每个商品的id都不相同,且不会漏过任何一个id,生产者没有重复生产,消费者没有重复消费,结果完全正确.
1.2.使用线程对象,多个生产者线程,多个消费者线程,1个缓存位置 。
1.2.1一个经典的bug 。
对于多生产者,多消费者这个问题,看起来我们似乎不用修改代码,只需在main方法中多添加几个线程就好。假设我们需要三个消费者,一个生产者,那么我们只需要在main方法中再添加两个消费者线程.
1
2
3
4
5
6
7
8
9
|
public
static
void
main(string[] args)
throws
interruptedexception{
productercomsumerdemo1 pcd =
new
productercomsumerdemo1();
runnable c = pcd.
new
comsumethread();
runnable p = pcd.
new
productthread();
new
thread(c).start();
new
thread(p).start();
new
thread(c).start();
new
thread(c).start();
}
|
运行结果 。
1
2
3
4
5
6
7
8
9
10
11
|
name: b, price:
1
, id:
1
name: a, price:
2
, id:
2
name: a, price:
2
, id:
2
name: b, price:
1
, id:
3
name: b, price:
1
, id:
3
name: a, price:
2
, id:
4
name: a, price:
2
, id:
4
name: b, price:
1
, id:
5
name: b, price:
1
, id:
5
name: a, price:
2
, id:
6
……
|
从结果中,我们发现消费者重复消费了商品,所以这样做显然是错误的。这里我们定义多个消费者,一个生产者,所以遇到了重复消费的问题,如果定义成一个消费者,多个生产者就会遇到id覆盖的问题。如果我们定义多个消费者,多个生产者,那么即会遇到重复消费,也会遇到id覆盖的问题。注意,上面的代码使用的notifyall唤醒方法,如果使用notify方法唤醒bug仍然可能发生.
现在我们来分析一下原因。当生产者生产好了商品,会唤醒因没有商品而阻塞消费者线程,假设唤醒的消费者线程超过两个,这两个线程会竞争获取锁,获取到锁的线程就会从obj.wait()方法中返回,然后消费商品,并把isfull置为false,然后释放锁。当被唤醒的另一个线程竞争获取到锁了以后也会从obj.wait()方法中返回。会再次消费同一个商品。显然,每一个被唤醒的线程应该再次检查isfull这个条件。所以无论是消费者,还是生产者,isfull的判断必须改成while循环,这样才能得到正确的结果而不受生产者的线程数和消费者的线程数的影响.
而对于只有一个生产者线程,一个消费者线程,用if判断是没有问题的,但是仍然强烈建议改成while语句进行判断.
1.2.2正确的姿势 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
package
demo;
import
java.util.random;
/*使用线程对象,一个缓存位置,一个生产者,一个消费者,无限生产商品消费商品*/
public class productercomsumerdemo1 {
/*定义一个商品缓存位置*/
private volatile goods goods;
/*定义一个对象作为锁,不使用goods作为锁是因为生产者每次会产生一个新的对象*/
private object obj = new object();
/*isfull == true 生产者线程休息,消费者线程消费
*isfull == false 消费者线程消费,生产者线程生产*/
private volatile boolean isfull = false;
/*商品的id编号,生产者制造的每个商品的id都不一样,每生产一个id自增1*/
private int id = 1;
/*随机产生一个sleep时间*/
private random rnd = new random();
/*=================定义消费者线程==================*/
public class comsumethread implements runnable{
@override
public void run(){
try{
while(true){
/*获取obj对象的锁, id 和 isfull 的操作都在同步代码块中*/
synchronized(obj){
while(!isfull){
/*wait方法使当前线程阻塞,并释放锁*/
obj.wait();
}
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
/*模拟消费商品*/
system.out.println(goods);
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
isfull = false;
/*唤醒阻塞obj上的生产者线程*/
obj.notifyall();
}
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
}
}
catch (interruptedexception e){
/*我就是任性,这里什么都不做*/
}
}
}
/*=================定义生产者线程==================*/
public class productthread implements runnable{
@override
public void run(){
try {
while(true){
synchronized(obj){
while(isfull){
obj.wait();
}
thread.sleep(rnd.nextint(500));
/*如果id为偶数,生产价格为2的产品a
如果id为奇数,生产价格为1的产品b*/
if(id % 2 == 0){
goods = new goods("a", 2, id);
} else{
goods = new goods("b", 1, id);
}
thread.sleep(rnd.nextint(250));
id++;
isfull = true;
/*唤醒阻塞的消费者线程*/
obj.notifyall();
}
}
}
catch (interruptedexception e) {
/*我就是任性,这里什么都不做*/
}
}
}
public
static
void
main(string[] args)
throws
interruptedexception{
productercomsumerdemo1 pcd =
new
productercomsumerdemo1();
runnable c = pcd.
new
comsumethread();
runnable p = pcd.
new
productthread();
new
thread(p).start();
new
thread(p).start();
new
thread(p).start();
new
thread(c).start();
new
thread(c).start();
new
thread(c).start();
}
}
|
1.3使用线程对象,多个缓存位置(有界),多生产者,多消费者 。
1)当缓存位置满时,我们应该阻塞生产者线程 。
2)当缓存位置空时,我们应该阻塞消费者线程 。
下面的代码我没有用java对象内置的锁,而是用了reentrantlock对象。是因为普通对象的锁只有一个阻塞队列,如果使用notify方式,无法保证唤醒的就是特定类型的线程(消费者线程或生产者线程),而notifyall方法会唤醒所有的线程,当剩余的缓存商品的数量小于生产者线程数量或已缓存商品的数量小于消费者线程时效率就比较低。所以这里我们通过reentrantlock对象构造两个阻塞队列提高效率.
1.3.1普通方式 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
package
demo;
import
java.util.linkedlist;
import
java.util.random;
import
java.util.concurrent.locks.condition;
import
java.util.concurrent.locks.lock;
import
java.util.concurrent.locks.reentrantlock;
/*使用线程对象,多个缓存位置(有界),多生产者,多消费者,无限循环模式*/
public class productercomsumerdemo2 {
/*最大缓存商品数*/
private final int max_slot = 2;
/*定义缓存商品的容器*/
private linkedlist<goods> queue = new linkedlist<goods>();
/*定义线程锁和锁对应的阻塞队列*/
private lock lock = new reentrantlock();
private condition full = lock.newcondition();
private condition empty = lock.newcondition();
/*商品的id编号,生产者制造的每个商品的id都不一样,每生产一个id自增1*/
private int id = 1;
/*随机产生一个sleep时间*/
private random rnd = new random();
/*=================定义消费者线程==================*/
public class comsumethread implements runnable{
@override
public void run(){
while(true){
/*加锁,queue的出列操作都在同步代码块中*/
lock.lock();
try {
while(queue.isempty()){
system.out.println("queue is empty");
empty.await();
}
/*随机延时一段时间*/
thread.sleep(rnd.nextint(200));
/*模拟消费商品*/
goods goods = queue.remove();
system.out.println(goods);
/*随机延时一段时间*/
thread.sleep(rnd.nextint(200));
/*唤醒阻塞的生产者线程*/
full.signal();
}
catch (interruptedexception e) {
/*什么都不做*/
}
finally{
lock.unlock();
}
/*释放锁后随机延时一段时间*/
try {
thread.sleep(rnd.nextint(200));
}
catch (interruptedexception e) {
/*什么都不做*/
}
}
}
}
/*=================定义生产者线程==================*/
public class productthread implements runnable{
@override
public void run(){
while(true){
/*加锁,queue的入列操作,id操作都在同步代码块中*/
lock.lock();
try{
while(queue.size() == max_slot){
system.out.println("queue is full");
full.await();
}
thread.sleep(rnd.nextint(200));
goods goods = null;
/*根据序号产生不同的商品*/
switch(id%3){
case 0 : goods = new goods("a", 1, id);
break;
case 1 : goods = new goods("b", 2, id);
break;
case 2 : goods = new goods("c", 3, id);
break;
}
thread.sleep(rnd.nextint(200));
queue.add(goods);
id++;
/*唤醒阻塞的消费者线程*/
empty.signal();
}
catch(interruptedexception e){
/*什么都不做*/
}
finally{
lock.unlock();
}
/*释放锁后随机延时一段时间*/
try {
thread.sleep(rnd.nextint(100));
}
catch (interruptedexception e) {
/*什么都不做*/
}
}
}
}
/*=================main==================*/
public static void main(string[] args) throws interruptedexception{
productercomsumerdemo2 pcd = new productercomsumerdemo2();
runnable c = pcd.new comsumethread();
runnable p = pcd.new productthread();
/*两个生产者线程,两个消费者线程*/
new
thread(p).start();
new
thread(p).start();
new
thread(c).start();
new
thread(c).start();
}
}
|
运行结果 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
queue is empty
queue is empty
name: b, price:
2
, id:
1
name: c, price:
3
, id:
2
name: a, price:
1
, id:
3
queue is full
name: b, price:
2
, id:
4
name: c, price:
3
, id:
5
queue is full
name: a, price:
1
, id:
6
name: b, price:
2
, id:
7
name: c, price:
3
, id:
8
name: a, price:
1
, id:
9
name: b, price:
2
, id:
10
name: c, price:
3
, id:
11
name: a, price:
1
, id:
12
name: b, price:
2
, id:
13
name: c, price:
3
, id:
14
……
|
1.3.2 更优雅的实现方式 。
下面使用线程池(threadpool)和阻塞队列(linkedblockingqueue)原子类(atomicinteger)以更加优雅的方式实现上述功能。linkedblockingqueue阻塞队列仅在take和put方法上锁,所以id必须定义为原子类.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
package
demo;
import
java.util.random;
import
java.util.concurrent.executorservice;
import
java.util.concurrent.executors;
import
java.util.concurrent.linkedblockingqueue;
import
java.util.concurrent.atomic.atomicinteger;
/*使用线程对象,多个缓存位置(有界),多生产者,多消费者,无限循环模式*/
public class productercomsumerdemo4 {
/*最大缓存商品数*/
private final int max_slot = 3;
/*定义缓存商品的容器*/
private linkedblockingqueue<goods> queue = new linkedblockingqueue<goods>(max_slot);
/*商品的id编号,生产者制造的每个商品的id都不一样,每生产一个id自增1*/
private atomicinteger id = new atomicinteger(1);
/*随机产生一个sleep时间*/
private random rnd = new random();
/*=================定义消费者线程==================*/
public class comsumethread implements runnable{
@override
public void run(){
while(true){
try {
/*随机延时一段时间*/
thread.sleep(rnd.nextint(200));
/*模拟消费商品*/
goods goods = queue.take();
system.out.println(goods);
/*随机延时一段时间*/
thread.sleep(rnd.nextint(200));
}
catch (interruptedexception e) {
/*什么都不做*/
}
}
}
}
/*=================定义生产者线程==================*/
public class productthread implements runnable{
@override
public void run(){
while(true){
try{
int x = id.getandincrement();
goods goods = null;
thread.sleep(rnd.nextint(200));
/*根据序号产生不同的商品*/
switch(x%3){
case 0 : goods = new goods("a", 1, x);
break;
case 1 : goods = new goods("b", 2, x);
break;
case 2 : goods = new goods("c", 3, x);
break;
}
thread.sleep(rnd.nextint(200));
queue.put(goods);
thread.sleep(rnd.nextint(100));
}
catch(interruptedexception e){
/*什么都不做*/
}
}
}
}
/*=================main==================*/
public static void main(string[] args) throws interruptedexception{
productercomsumerdemo4 pcd = new productercomsumerdemo4();
runnable c = pcd.new comsumethread();
runnable p = pcd.new productthread();
/*定义线程池*/
executorservice es = executors.newcachedthreadpool();
/*三个生产者线程,两个消费者线程*/
es.execute(p);
es.execute(p);
es.execute(p);
es.execute(c);
es.execute(c);
es.shutdown();
}
}
|
2.有限商品个数 。
这个问题显然比上面的问题要复杂不少,原因在于要保证缓存区的商品要全部消费掉,没有重复消费商品,没有覆盖商品,同时还要保证所有线程能够正常结束,防止存在一直阻塞的线程.
2.1使用线程对象,多个缓存位置(有界),多生产者,多消费者 。
思路定义一下三个变量 。
1
2
3
4
5
6
7
8
|
/*需要生产的总商品数*/
private final int total_num = 30;
/*已产生的数量*/
private volatile int productnum = 0;
/*已消耗的商品数*/
private
volatile
int
comsumednum =
0
;
|
每生产一个商品 productnum 自增1,直到total_num为止,如果不满足条件 productnum < total_num 则结束进程,自增操作必须在full.await()方法调用之前,防止生产者线程无法唤醒.
同理,每消费一个商品 comsumednum 自增1,直到total_num为止,如果不满足条件 comsumednum < total_num 则结束进程,自增操作必须在empty.await()方法调用之前,防止消费者线程无法唤醒.
comsumednum和productnum相当于计划经济时代的粮票一样,有了它能够保证生产者线程在唤醒后一定需要生产一个商品,消费者线程在唤醒以后一定能够消费一个商品 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
package
demo;
import
java.util.linkedlist;
import
java.util.random;
import
java.util.concurrent.locks.condition;
import
java.util.concurrent.locks.lock;
import
java.util.concurrent.locks.reentrantlock;
/*使用线程对象,多个缓存位置(有界),多生产者,多消费者, 有限商品个数*/
public class productercomsumerdemo3 {
/*需要生产的总商品数*/
private final int total_num = 30;
/*已产生的数量*/
private volatile int productnum = 0;
/*已消耗的商品数*/
private volatile int comsumednum = 0;
/*最大缓存商品数*/
private final int max_slot = 2;
/*定义线程公用的锁和条件*/
private lock lock = new reentrantlock();
private condition full = lock.newcondition();
private condition empty = lock.newcondition();
/*定义缓存商品的容器*/
private linkedlist<goods> queue = new linkedlist<goods>();
/*商品的id编号,生产者制造的每个商品的id都不一样,每生产一个id自增1*/
private int id = 1;
/*随机产生一个sleep时间*/
private random rnd = new random();
/*=================定义消费者线程==================*/
public class comsumethread implements runnable{
@override
public void run(){
while(true){
/*加锁, id、comsumednum 操作都在同步代码块中*/
lock.lock();
try {
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
if(comsumednum < total_num){
comsumednum++;
} else{
/*这里会自动执行finally的语句,释放锁*/
break;
}
while(queue.isempty()){
system.out.println("queue is empty");
empty.await();
}
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
/*模拟消费商品*/
goods goods = queue.remove();
system.out.println(goods);
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
/*唤醒阻塞的生产者线程*/
full.signal();
}
catch (interruptedexception e) {
}
finally{
lock.unlock();
}
/*释放锁后,随机延时一段时间*/
try {
thread.sleep(rnd.nextint(250));
}
catch (interruptedexception e) {
}
}
system.out.println(
"customer "
+ thread.currentthread().getname()
+ " is over");
}
}
/*=================定义生产者线程==================*/
public class productthread implements runnable{
@override
public void run(){
while(true){
lock.lock();
try{
/*随机延时一段时间*/
thread.sleep(rnd.nextint(250));
if(productnum < total_num){
productnum++;
} else{
/*这里会自动执行finally的语句,释放锁*/
break;
}
thread.sleep(rnd.nextint(250));
while(queue.size() == max_slot){
system.out.println("queue is full");
full.await();
}
thread.sleep(rnd.nextint(250));
goods goods = null;
/*根据序号产生不同的商品*/
switch(id%3){
case 0 : goods = new goods("a", 1, id);
break;
case 1 : goods = new goods("b", 2, id);
break;
case 2 : goods = new goods("c", 3, id);
break;
}
queue.add(goods);
id++;
/*唤醒阻塞的消费者线程*/
empty.signal();
}
catch(interruptedexception e){
}
finally{
lock.unlock();
}
/*释放锁后,随机延时一段时间*/
try {
thread.sleep(rnd.nextint(250));
}
catch (interruptedexception e) {
/*什么都不做*/
}
}
system.out.println(
"producter "
+ thread.currentthread().getname()
+ " is over");
}
}
/*=================main==================*/
public
static
void
main(string[] args)
throws
interruptedexception{
productercomsumerdemo3 pcd =
new
productercomsumerdemo3();
comsumethread c = pcd.
new
comsumethread();
productthread p = pcd.
new
productthread();
new
thread(p).start();
new
thread(p).start();
new
thread(p).start();
new
thread(c).start();
new
thread(c).start();
new
thread(c).start();
system.out.println(
"main thread is over"
);
}
}
|
2.2利用线程池,原子类,阻塞队列,以更优雅的方式实现 。
linkedblockingqueue阻塞队列仅在take和put方法上锁,所以productnum和comsumednum必须定义为原子类.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
package
demo;
import
java.util.random;
import
java.util.concurrent.countdownlatch;
import
java.util.concurrent.executorservice;
import
java.util.concurrent.executors;
import
java.util.concurrent.linkedblockingqueue;
import
java.util.concurrent.atomic.atomicinteger;
/*使用线程池,多个缓存位置(有界),多生产者,多消费者, 有限商品个数*/
public class linkedblockingqueuedemo {
/*需要生产的总商品数*/
private final int total_num = 20;
/*已产生商品的数量*/
volatile atomicinteger productnum = new atomicinteger(0);
/*已消耗的商品数*/
volatile atomicinteger comsumednum = new atomicinteger(0);
/*最大缓存商品数*/
private final int max_slot = 5;
/*同步阻塞队列,队列容量为max_slot*/
private linkedblockingqueue<goods> lbq = new linkedblockingqueue<goods>(max_slot);
/*随机数*/
private random rnd = new random();
/*pn表示产品的编号,产品编号从1开始*/
private volatile atomicinteger pn = new atomicinteger(1);
/*=================定义消费者线程==================*/
public class customerthread implements runnable{
@override
public void run(){
while(comsumednum.getandincrement() < total_num){
try{
/*随机延时一段时间*/
thread.sleep(rnd.nextint(500));
/*从队列中取出商品,队列空时发生阻塞*/
goods goods = lbq.take();
/*随机延时一段时间*/
thread.sleep(rnd.nextint(500));
/*模拟消耗商品*/
system.out.println(goods);
/*随机延时一段时间*/
thread.sleep(rnd.nextint(500));
}
catch(interruptedexception e){
}
}
system.out.println(
"customer "
+ thread.currentthread().getname()
+ " is over");
}
}
/*=================定义生产者线程==================*/
public class producerthread implements runnable{
@override
public void run(){
while(productnum.getandincrement() < total_num){
try {
int x = pn.getandincrement();
goods goods = null;
/*根据序号产生不同的商品*/
switch(x%3){
case 0 : goods = new goods("a", 1, x);
break;
case 1 : goods = new goods("b", 2, x);
break;
case 2 : goods = new goods("c", 3, x);
break;
}
/*随机延时一段时间*/
thread.sleep(rnd.nextint(500));
/*产生的新产品入列,队列满时发生阻塞*/
lbq.put(goods);
/*随机延时一段时间*/
thread.sleep(rnd.nextint(500));
}
catch (interruptedexception e1) {
/*什么都不做*/
}
}
system.out.println(
"producter "
+ thread.currentthread().getname()
+ " is over ");
}
}
/*=================main==================*/
public
static
void
main(string[] args){
linkedblockingqueuedemo lbqd =
new
linkedblockingqueuedemo();
runnable c = lbqd.
new
customerthread();
runnable p = lbqd.
new
producerthread();
executorservice es = executors.newcachedthreadpool();
es.execute(c);
es.execute(c);
es.execute(c);
es.execute(p);
es.execute(p);
es.execute(p);
es.shutdown();
system.out.println(
"main thread is over"
);
}
}
|
总结 。
以上就是本文关于java多线程中不同条件下编写生产消费者模型方法介绍的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出.
原文链接:http://www.cnblogs.com/nullzx/p/7798504.html 。
最后此篇关于Java多线程中不同条件下编写生产消费者模型方法介绍的文章就讲到这里了,如果你想了解更多关于Java多线程中不同条件下编写生产消费者模型方法介绍的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
晚上在 QQ 上看到昵称为“乱码”的好友回答了搜搜问问里一个问题: 在VBS中有办法定义字节数组么? 在VBS中有办法定义字节数组么?就是字节子类型数组(VarType是8209的那种)注意不是V
例如,员工管理应用程序可能包括一个EmPloyee 类。然后可以用这个类来创建和维护特定实例,比如Gonn和Sally。 根据预定义的类创建对象常称为类的实例化(class insta
在自然语言中,我们理解抽象的概念是,一个物体的一种大的描述,这种描述对某类物体来说是共有的特性。那么在PHP中也是一样的,我们把一个类进行抽象,可以指明类的一般行为,这个类应该是一个模板,它指示它的
DBA_2PC_PENDING Oracle会自动处理分布事务,保证分布事务的一致性,所有站点全部提交或全部回滚。一般情况下,处理过程在很短的时间内完成,根本无法察觉到。但是,如果在commit或
目录 计算过程 投影分量计算 假设你有一家理发店,已经记录了过去一年中所有顾客的头发长度和发型偏好的数据。现在你想从这些数据中提取一些主要的信息,比如顾客最常
Object.defineProperty函数会直接在一个对象上定义一个新的属性,或者修改一个对象的现有属性,并返回此对象。 一、简单使用 const obj = {} Object.defineP
SPL官网 http://www.scudata.com.cn/ 介绍 业务逻辑经常包含较复杂的流程和计算,同时涉及数据库的读写。由于授权麻烦、影响数据库安全、无法迁移、技术要求高、编写困难等原因,很
SPL官网 http://www.scudata.com.cn/ 介绍 业务逻辑经常包含较复杂的流程和计算,同时涉及数据库的读写。由于授权麻烦、影响数据库安全、无法迁移、技术要求高、编写困难等原因,很
一 点睛 Thrift 是一歀基于 CS 架构的 RPC 框架,最初由 Facebook 研发,2008 年转入 Apache 组织。开发人员可以使用 Thrift 提供的 IDL(接口定义语言)来定
数据库应用程序与主应用程序分开存在,并存储数据集合。 每个数据库都使用一个或多个API来创建,访问,管理,搜索和复制其包含的数据。 数据库还使用非关系数据源,例如对象或文件。 然而,数据库证明是大数
介绍 Ant是一个 Apache 基金会下的跨平台的基于 Java 语言开发的构件工具。在我们详细了解 Apache Ant 之前, 让我们来讲解为什么构建工具是需要最先了解的。 构建工具的需求
我现在正在尝试学习ocaml,并希望从一个小程序开始,生成所有位组合: [“0”,“0”,“0”] [“0”,“0”,“1”] [“0”,“1”,“0”] ... 等等 我的想法是下面的代码: let
我正在做我的介绍 C 类(class)作业,我的任务是执行以下任务...... 为一个函数编写代码,该函数通过值接收两个参数(a 和 b)并通过引用具有另外两个参数(c 和 d)。所有参数都是双倍的。
我希望提供有关我网站内容的快速演示,以及如何在用户访问我的页面后立即以正确的方式使用它们。我希望使用顶部的弹出式窗口进行演示。 我的意思是小信息框,一个接一个地通知用户各个步骤。任何人都可以帮助我如何
与C、Java等语言一样,JavaScript中可以用&&、||、!三个逻辑判断符来对boolean值进行逻辑判断。与C、Java不同的是,JavaScript中逻辑与(&&
JavaScript中,==与===操作符均可用于判断两个值是否相等;不同之处在于,如果进行判断的两个值类型不一致,===操作符会直接返回false,而==操作符则会在类型转换后再进行判断。详细的判
JavaScript中,object转换为boolean的操作非常简单:所有的object转换成boolean后均为true;即使是new Boolean(false)这样的object在转换为bo
在android开发中,当不满足触发条件就按返回键的时候,就要对此进行检测。尤其是当前Activity需要往前一个Activity传送消息时。即Activity1跳转到Activity3如果采用的是
背景 当要求系统启动一个应用程序时,系统会先查找当前命令是否是内部命令,若不是,则在当前目录下查找,如果仍没有找到,则在系统变量 Path 指定的路径去查找。JDK(Java Developmen
概述 想做一个微信的公众平台,阅读了微信官方给的网址接入的示例代码,发现有个问题好像一直都是半知半解的,就是在类里边直接使用$_GET。仔细查了下关于这方面的知识,发现PHP中这部分的基础知识掌握
我是一名优秀的程序员,十分优秀!