线程---生产者消费者问题
生活随笔
收集整理的這篇文章主要介紹了
线程---生产者消费者问题
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在開始之前先簡單回顧一下生產(chǎn)者消費(fèi)者問題:一群生產(chǎn)者在生產(chǎn)消息,并將此消息提供給消費(fèi)者去消費(fèi)。它們中間設(shè)了具有N個(gè)緩存區(qū)的緩沖池,生產(chǎn)者每次可將生產(chǎn)的消息放入一個(gè)緩存區(qū)內(nèi),消費(fèi)者每次可將一個(gè)緩存區(qū)內(nèi)的消息拿出來消費(fèi)。但這個(gè)過程有兩個(gè)條件:任何一方操作一個(gè)緩沖區(qū)時(shí)不能有其它同時(shí)對(duì)該緩沖區(qū)進(jìn)行操作;只有當(dāng)緩沖區(qū)還有空余,生產(chǎn)者才能生產(chǎn),只有當(dāng)緩沖區(qū)至少有一個(gè)產(chǎn)品,消費(fèi)者才能從中取出來消費(fèi)。這里兩個(gè)條件分別對(duì)應(yīng)了互斥和同步。
生產(chǎn)者與消費(fèi)者模型中,要保證以下幾點(diǎn):
1 同一時(shí)間內(nèi)只能有一個(gè)生產(chǎn)者生產(chǎn)
2 同一時(shí)間內(nèi)只能有一個(gè)消費(fèi)者消費(fèi)
3 生產(chǎn)者生產(chǎn)的同時(shí)消費(fèi)者不能消費(fèi)
4 消息隊(duì)列滿時(shí)生產(chǎn)者不能繼續(xù)生產(chǎn)
5 消息隊(duì)列空時(shí)消費(fèi)者不能繼續(xù)消費(fèi)
[b]正文:[/b]
首先先建一個(gè)使用多線程的寫的生產(chǎn)者消費(fèi)者的通用類,在生產(chǎn)方法中(produce()),如果隊(duì)列中已經(jīng)有五個(gè)大餅,就提示消息,等待消費(fèi)者消費(fèi)大餅,否則往隊(duì)列中添加大餅。在消費(fèi)方法中(consume()),如果隊(duì)列中沒有大餅,則提示消息,等待生產(chǎn)者生產(chǎn)大餅,否則就刪除一條大餅消息。
import java.util.ArrayList;
import java.util.List;
public class Stack {
List<Message> stack = new ArrayList<Message>();
private int MAX_MESSAGE_NUM = 5;
public Stack(){
System.out.println("大餅生產(chǎn)基地!");
}
//加上互斥鎖
public synchronized void produce(Message message){
while( stack.size() == MAX_MESSAGE_NUM ){
try{
System.out.println(Thread.currentThread().getName() + " 隊(duì)列滿!等待消費(fèi)...");
this.wait();
}catch(InterruptedException e){
}
}
stack.add(message);
System.out.println(Thread.currentThread().getName() + " 正在生產(chǎn)" + message.getContent() + " 當(dāng)前大餅個(gè)數(shù):" + stack.size());
this.notify();
}
//加上互斥鎖
public synchronized void consume(){
while(stack.size() == 0){
try{
System.out.println("隊(duì)列空,無大餅,請(qǐng)等待...");
this.wait();
}catch(InterruptedException e){
}
}
Message message = stack.get(0);
stack.remove(0);
System.out.println(Thread.currentThread().getName() + " 正在消費(fèi)"
+ message.getContent() + " ,當(dāng)前大餅個(gè)數(shù): " + stack.size());
this.notify();
}
}
創(chuàng)建個(gè)消息對(duì)象。
public class Message {
public static int id;
public String content;
public static int getId() {
return id;
}
public static void setId(int id) {
Message.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
生產(chǎn)者類,主要產(chǎn)生消息,注意繼承了Thread并實(shí)現(xiàn)了run,并且有一個(gè)對(duì)Stack實(shí)例的引用,主要調(diào)用了Stack的produce方法
class Producer extends Thread {
private Stack stack;
public Producer(Stack s){
this.stack = s;
}
public void run (){
while(true){
Message message = new Message();
message.setId(++ Message.id);
message.setContent("大餅" + Message.id);
stack.produce(message);
try{
sleep(100);
}catch(Exception e){
}
}
}
}
消費(fèi)者類,主要消費(fèi)消息,跟生產(chǎn)者是對(duì)稱的,主要調(diào)用了Stack的consume方法。
class Consumer extends Thread {
private Stack stack;
Consumer(Stack stack) {
this.stack = stack;
}
public void run() {
while (true) {
stack.consume();
try {
sleep(100);
} catch (Exception e) {
}
}
}
}
主類,主要構(gòu)造出一個(gè)Stack并啟動(dòng)N個(gè)生產(chǎn)者和消費(fèi)者。
public class ThreadTest {
public static void main(String[] args) {
Stack s = new Stack();
Producer p1 = new Producer(s);
Producer p2 = new Producer(s);
Producer p3 = new Producer(s);
Consumer c1 = new Consumer(s);
Consumer c2 = new Consumer(s);
Consumer c3 = new Consumer(s);
Thread threadP1 = new Thread(p1, "thread-生產(chǎn)者--A");
Thread threadP2 = new Thread(p2, "thread-生產(chǎn)者--B");
Thread threadP3 = new Thread(p3, "thread-生產(chǎn)者--C");
Thread threadC1 = new Thread(c1, "thread-消費(fèi)者甲");
Thread threadC2 = new Thread(c2, "thread-消費(fèi)者乙");
Thread threadC3 = new Thread(c3, "thread-消費(fèi)者丙");
threadP1.start();
threadP2.start();
threadP3.start();
threadC1.start();
threadC2.start();
//threadC3.start();
}
}
從以上這個(gè)例子,可以看出來,通過一個(gè)Stack,我們將一個(gè)對(duì)象的創(chuàng)建和執(zhí)行分離開了(在生產(chǎn)者中創(chuàng)建,在消費(fèi)者中執(zhí)行,這種分離帶來了極大的好處。比如將費(fèi)時(shí)的執(zhí)行分開之后提高了創(chuàng)建線程的響應(yīng)性,并且它們之間的順序?qū)崿F(xiàn)了可控性,不用創(chuàng)建完了馬上就執(zhí)行,它們的分離使得可以分布式做創(chuàng)建和分離,從而出現(xiàn)了類似BMQ的消息中間件。
生產(chǎn)者與消費(fèi)者模型中,要保證以下幾點(diǎn):
1 同一時(shí)間內(nèi)只能有一個(gè)生產(chǎn)者生產(chǎn)
2 同一時(shí)間內(nèi)只能有一個(gè)消費(fèi)者消費(fèi)
3 生產(chǎn)者生產(chǎn)的同時(shí)消費(fèi)者不能消費(fèi)
4 消息隊(duì)列滿時(shí)生產(chǎn)者不能繼續(xù)生產(chǎn)
5 消息隊(duì)列空時(shí)消費(fèi)者不能繼續(xù)消費(fèi)
[b]正文:[/b]
首先先建一個(gè)使用多線程的寫的生產(chǎn)者消費(fèi)者的通用類,在生產(chǎn)方法中(produce()),如果隊(duì)列中已經(jīng)有五個(gè)大餅,就提示消息,等待消費(fèi)者消費(fèi)大餅,否則往隊(duì)列中添加大餅。在消費(fèi)方法中(consume()),如果隊(duì)列中沒有大餅,則提示消息,等待生產(chǎn)者生產(chǎn)大餅,否則就刪除一條大餅消息。
import java.util.ArrayList;
import java.util.List;
public class Stack {
List<Message> stack = new ArrayList<Message>();
private int MAX_MESSAGE_NUM = 5;
public Stack(){
System.out.println("大餅生產(chǎn)基地!");
}
//加上互斥鎖
public synchronized void produce(Message message){
while( stack.size() == MAX_MESSAGE_NUM ){
try{
System.out.println(Thread.currentThread().getName() + " 隊(duì)列滿!等待消費(fèi)...");
this.wait();
}catch(InterruptedException e){
}
}
stack.add(message);
System.out.println(Thread.currentThread().getName() + " 正在生產(chǎn)" + message.getContent() + " 當(dāng)前大餅個(gè)數(shù):" + stack.size());
this.notify();
}
//加上互斥鎖
public synchronized void consume(){
while(stack.size() == 0){
try{
System.out.println("隊(duì)列空,無大餅,請(qǐng)等待...");
this.wait();
}catch(InterruptedException e){
}
}
Message message = stack.get(0);
stack.remove(0);
System.out.println(Thread.currentThread().getName() + " 正在消費(fèi)"
+ message.getContent() + " ,當(dāng)前大餅個(gè)數(shù): " + stack.size());
this.notify();
}
}
創(chuàng)建個(gè)消息對(duì)象。
public class Message {
public static int id;
public String content;
public static int getId() {
return id;
}
public static void setId(int id) {
Message.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
生產(chǎn)者類,主要產(chǎn)生消息,注意繼承了Thread并實(shí)現(xiàn)了run,并且有一個(gè)對(duì)Stack實(shí)例的引用,主要調(diào)用了Stack的produce方法
class Producer extends Thread {
private Stack stack;
public Producer(Stack s){
this.stack = s;
}
public void run (){
while(true){
Message message = new Message();
message.setId(++ Message.id);
message.setContent("大餅" + Message.id);
stack.produce(message);
try{
sleep(100);
}catch(Exception e){
}
}
}
}
消費(fèi)者類,主要消費(fèi)消息,跟生產(chǎn)者是對(duì)稱的,主要調(diào)用了Stack的consume方法。
class Consumer extends Thread {
private Stack stack;
Consumer(Stack stack) {
this.stack = stack;
}
public void run() {
while (true) {
stack.consume();
try {
sleep(100);
} catch (Exception e) {
}
}
}
}
主類,主要構(gòu)造出一個(gè)Stack并啟動(dòng)N個(gè)生產(chǎn)者和消費(fèi)者。
public class ThreadTest {
public static void main(String[] args) {
Stack s = new Stack();
Producer p1 = new Producer(s);
Producer p2 = new Producer(s);
Producer p3 = new Producer(s);
Consumer c1 = new Consumer(s);
Consumer c2 = new Consumer(s);
Consumer c3 = new Consumer(s);
Thread threadP1 = new Thread(p1, "thread-生產(chǎn)者--A");
Thread threadP2 = new Thread(p2, "thread-生產(chǎn)者--B");
Thread threadP3 = new Thread(p3, "thread-生產(chǎn)者--C");
Thread threadC1 = new Thread(c1, "thread-消費(fèi)者甲");
Thread threadC2 = new Thread(c2, "thread-消費(fèi)者乙");
Thread threadC3 = new Thread(c3, "thread-消費(fèi)者丙");
threadP1.start();
threadP2.start();
threadP3.start();
threadC1.start();
threadC2.start();
//threadC3.start();
}
}
從以上這個(gè)例子,可以看出來,通過一個(gè)Stack,我們將一個(gè)對(duì)象的創(chuàng)建和執(zhí)行分離開了(在生產(chǎn)者中創(chuàng)建,在消費(fèi)者中執(zhí)行,這種分離帶來了極大的好處。比如將費(fèi)時(shí)的執(zhí)行分開之后提高了創(chuàng)建線程的響應(yīng)性,并且它們之間的順序?qū)崿F(xiàn)了可控性,不用創(chuàng)建完了馬上就執(zhí)行,它們的分離使得可以分布式做創(chuàng)建和分離,從而出現(xiàn)了類似BMQ的消息中間件。
總結(jié)
以上是生活随笔為你收集整理的线程---生产者消费者问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 中的日期与时间
- 下一篇: 深度-图像风格变换【二】