经典线程同步问题(生产者&消费者)

转载 2012年03月29日 15:50:43

生产者-消费者(producer-consumer)问题是一个著名的线程同步问题。它描述的是:有一群生产者线程在生产产品,并将这些产品提供给消费者线程去消费。

为使生产者与消费者之间能够并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者将它所生产的产品放入一个缓冲区中;消费者可以从一个缓冲区中取走产品产生消费。

尽管所有的生产者线程和消费者线程都是以异步方式运行的,但他们之间必须保持同步,即不允许消费者到一个空缓冲区去消费,也不允许生产者向一个已经被占用的缓冲区投放产品。

我把这个问题复杂化,设立m个缓冲池,每个缓冲池都有各自固定的容量,每个生产者或消费者在进行生产消费活动之前,先选择一个缓冲池。由此会引发一个线程死锁的问题:所有的生产者都在满的缓冲池等待,直到某个消费者取走一个产品,释放出一块缓冲区;同时所有的消费者都在空的缓冲池等待,直到某个生产者放进一个产品。

解决方法:记录每一个线程的等待状态,如果当前线程会产生等待,则检测是否会产生死锁(所有线程都在等待),如果会产生死锁,拒绝此次生产消费活动(换一个缓冲池)

 

Java Code

 

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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
publicclassProducerAndConsumer {//作者:xelz,博客http://www.cnblogs.com/mingcn
      
    privatestaticfinal intPRODUCTION_LINE_COUNT =20;//生产线(缓冲池)条数
    privatestaticfinal intPRODUCTION_LINE_SIZE =100;//生产线最大容量
    privatestaticfinal intPRODUCER_COUNT =50;//生产者个数
    privatestaticfinal intCONSUMER_COUNT =50;//消费者个数
      
    publicstaticvoid main(String[] args) {
        ProductionLine[] productionLine =newProductionLine[PRODUCTION_LINE_COUNT];
        Producer[] producer =newProducer[PRODUCER_COUNT];
        Consumer[] consumer =newConsumer[CONSUMER_COUNT];
        SyncLock.initLock(PRODUCER_COUNT, CONSUMER_COUNT);//初始化每个线程的等待状态
        for(inti = 0; i < PRODUCTION_LINE_COUNT; i++) {//初始化每条生产线,随机容量
            productionLine[i] =newProductionLine((int) (Math.random() * PRODUCTION_LINE_SIZE) +1, i);
        }
        for(inti = 0; i < PRODUCER_COUNT; i++) {//初始化生产者线程
            producer[i] =newProducer(i, productionLine);
            newThread(producer[i]).start();
        }
        for(inti = 0; i < CONSUMER_COUNT; i++) {//初始化消费者线程
            consumer[i] =newConsumer(i, productionLine);
            newThread(consumer[i]).start();
        }
    }
      
}
  
classProduct {//产品(缓冲区)类
      
    intproductID;//制造者编号
    intproductionLineID;//生产线编号
    intproducerID;//产品编号(产品在该生产线上的位置)
      
    Product(intproducerID) {
        this.producerID = producerID;
    }
      
}
  
classProductionLine {//生产线(缓冲池)类
      
    Product[] product;//缓冲池采用循环队列模式
    intsize;//缓冲池大小
    intcount;//缓冲池当前产品计数
    intproductionLineID;//生产线编号
    intproduceID;//队头指针,下一个被放入的产品的编号
    intconsumeID;//队尾指针,下一个被取走的产品的编号
      
    ProductionLine(intsize,intproductionLineID) {//初始化生产线(缓冲池)
        this.size = size;
        this.productionLineID = productionLineID;
        product =newProduct[size];
        for(inti = 0; i < size /2; i++) {//为防止刚开始产销不平衡,预先放置一半产品
            putProduct(newProduct(-1));//产品生产者编号-1,系统制造
        }
    }
      
    booleanisFull() {//判断缓冲池是否满
        returncount == size;
    }
      
    booleanisEmpty() {//判断缓冲池是否空
        return0== count;
    }
      
    voidputProduct(Product product) {//放入一个产品,并将队头指针前移
        this.product[produceID] = product;
        product.productID = produceID;//给产品贴上标签,产品编号,生产线编号
        product.productionLineID = productionLineID;
        produceID = ++produceID % size;//下一个产品放置位置
        count++;
    }
      
    Product getProduct() {//取出一个产品,并将队尾指针前移
        Product product = this.product[consumeID];
        this.product[consumeID] =null;
        consumeID = ++consumeID % size;//下一个产品取出位置
        count--;
        returnproduct;
    }
      
}
  
classProducerimplementsRunnable {//生产者线程
      
    intproducerID;//自己的生产者编号
    ProductionLine[] productionLine;//共享的生产线
    ProductionLine currentProductionLine;
      
    Producer(intproducerID, ProductionLine[] productionLine) {
        this.producerID = producerID;
        this.productionLine = productionLine;
    }
      
    privatevoidproduce() {//生产活动
        Product product;
        intproductionLineID;
        while(true) {
            do{//选择一条生产线,若会产生死锁,则重选一条生产线
                productionLineID = (int) (Math.random() * productionLine.length);
                currentProductionLine = productionLine[productionLineID];
            }while((SyncLock.waitOnFull[producerID] = currentProductionLine.isFull()) && SyncLock.deadLock());
            //synchronized(SyncLock.printSyncLock) {
            //  System.out.print("Producer " + producerID +" wants to ");
            //  System.out.println("produce at ProductionLine  " + productionLineID);
            //}
            synchronized(currentProductionLine) {//同步对象:当前生产线,不能同时有两个及以上线程操作同一生产线
                while(currentProductionLine.isFull()) {//缓冲池满,无法生产,等待
                    try{
                        currentProductionLine.wait();
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                product =newProduct(producerID);//生产新的产品
                currentProductionLine.putProduct(product);//加入缓冲池
                synchronized(SyncLock.printSyncLock) {//打印生产线、生产者、产品ID及缓冲池是否变满
                    System.out.print("ProductionLine: "+ productionLineID);
                    System.out.print("\tProducer: "+ producerID);
                    System.out.print("\tProduct: "+ product.productID);
                    System.out.println(currentProductionLine.isFull() ?"\t("+ productionLineID + ")Full!":"");
                }//释放当前生产线同步锁
                currentProductionLine.notifyAll();//生产活动结束,唤醒当前生产线上等待的其他生产者/消费者线程
            }
            try{
                Thread.sleep((int) (Math.random() *1000));
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
      
    publicvoidrun() {
        produce();
    }
      
}
  
classConsumerimplementsRunnable {
      
    intconsumerID;//自己的消费者编号
    ProductionLine[] productionLine;//共享的生产线
    ProductionLine currentProductionLine;
      
    Consumer(intconsumerID, ProductionLine[] productionLine) {
        this.consumerID = consumerID;
        this.productionLine = productionLine;
    }
      
    privatevoidconsume() {//消费活动
        Product product;
        intproductionLineID;
        while(true) {
            do{//选择一条生产线,若会产生死锁,则重选一条生产线
                productionLineID = (int) (Math.random() * productionLine.length);
                currentProductionLine = productionLine[productionLineID];
            }while((SyncLock.waitOnEmpty[consumerID] = currentProductionLine.isEmpty()) && SyncLock.deadLock());
            //synchronized(SyncLock.printSyncLock) {
            //  System.out.print("Consumer " + consumerID +" wants to ");
            //  System.out.println("consume at ProductionLine  " + productionLineID);
            //}
            synchronized(currentProductionLine) {//同步对象:当前生产线,不能同时有两个及以上线程操作同一生产线
                while(currentProductionLine.isEmpty()) {//缓冲池空,无法消费,等待
                    try{
                        currentProductionLine.wait();
                    }catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                product = currentProductionLine.getProduct();//消费产品
                synchronized(SyncLock.printSyncLock) {//打印生产线、消费者、产品及其制造者ID,以及生产线是否变空
                    System.out.print("ProductionLine: "+ productionLineID);
                    System.out.print("\tConsumer: "+ consumerID);
                    System.out.print("\tProduct: "+ product.productID);
                    System.out.print("("+ product.producerID + ")");
                    System.out.println(currentProductionLine.isEmpty() ?"\t("+ productionLineID + ")Empty!":"");
                }
            currentProductionLine.notifyAll();//生产活动结束,唤醒当前生产线上等待的其他生产者/消费者线程
            }
            try{
                Thread.sleep((int) (Math.random() *1000));
            }catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
      
    publicvoidrun() {
        consume();
    }
      
}
  
classSyncLock {//提供死锁检测的静态方法,及打印同步
      
    staticfinalObject printSyncLock = newObject();//用于同步输出,防止不同线程输出交叉
    staticboolean[] waitOnEmpty;//指示某一消费者是否在空缓冲池等待
    staticboolean[] waitOnFull;//指示某一生产者是否在满缓冲池等待
      
    staticvoidinitLock(intProducerCount,intConsumerCount) {//初始化等待指示器
        waitOnEmpty =newboolean[ConsumerCount];
        waitOnFull =newboolean[ProducerCount];
    }
      
    staticbooleandeadLock() {//判断是否产生死锁
        for(booleanb : waitOnEmpty) {
            if(!b)returnfalse;
        }
        for(booleanb : waitOnFull) {
            if(!b)returnfalse;
        }
        returntrue;//若所有线程都在等待状态,则产生死锁
    }
      
}

【操作系统总结】经典的进程同步问题-生产者消费者问题

生产者消费者问题问题描述是:有一群生产者进程在生产产品,此产品提供给消费者去消费。为使生产者和消费者进程能并发执行,在它们之间设置一个具有n个缓冲池,生产者进程可将它所生产的产品放入一个缓冲池中,消费...
  • ttf1993
  • ttf1993
  • 2015年05月31日 12:55
  • 1827

进程间同步互斥经典问题(一)生产者-消费者问题

问题描述:生产者-消费者问题,也叫做缓存绑定问题(bounded-buffer),是一个多进程同步问题。 即有两个进程:制造少和消费者,共享一个固定大小的缓存 制造商的工作是制造一段数据...
  • qq_24451605
  • qq_24451605
  • 2015年11月01日 22:11
  • 3074

进程同步互斥经典题之消费者与生产者问题

操作系统进程同步互斥经典题之消费者与生产者问题
  • lj_2_0_2
  • lj_2_0_2
  • 2015年10月29日 21:00
  • 2591

多线程代码 经典线程同步互斥问题 生产者消费者问题

  • 2015年06月01日 22:06
  • 16KB
  • 下载

经典线程同步问题(生产者&消费者)--Java实现

====================================================== 注:本文源代码点此下载 =============================...
  • javazhuanzai
  • javazhuanzai
  • 2012年01月16日 02:30
  • 233

线程同步(生产者--消费者问题)

  • 2013年08月18日 20:46
  • 42KB
  • 下载

线程同步--生产者消费者问题

  • 2009年07月05日 22:15
  • 5KB
  • 下载

java线程同步经典——生产者消费者

/* * 生产者消费者问题,生产完之后要wait * 消费完之后要wait,没消费或生产一个就notify别的线程 * Object 的wait方法,指的是当前的正在访问本对象的线程wait, ...
  • wuer0520
  • wuer0520
  • 2013年11月16日 11:13
  • 354

线程同步经典案例-生产者与消费者模型-Java

一、相关知识简介      在生产者-消费者模型中,若只使用synchronized关键字实现对象锁,程序在运行中可能会出现以下两种情况: 若生产者的速度大于消费者,那么在消费者来不及取前一个数据之前...
  • Xminyang
  • Xminyang
  • 2016年11月18日 15:58
  • 905

线程同步之经典生产者-消费者模型

/* 线程同步之生产者-消费者模型 该模型符合以下要求: 1、生产者只在仓储未满时生产,仓满则停止生产; 2、消费者只在仓储未空时消费,仓空则等待; 3、当消费者发现仓储为空时则通知生产者...
  • kutekute
  • kutekute
  • 2012年10月15日 07:12
  • 1079
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:经典线程同步问题(生产者&消费者)
举报原因:
原因补充:

(最多只允许输入30个字)