簡述
生成者消費者模式,在併發編程模式裏面很常見。無邊界是指消息隊列,沒有設置,具體大小。
下面是常見的兩種模式通用類
MyTask : 定義了任務接口
package com.ricisung.Model.chapter1;
public abstract class MyTask {
abstract void doSomething();
}
SayHelloTask: 它是MyTask 的實現類; 主要打印一句hello
package com.ricisung.Model.chapter1;
public class SayHelloTask extends MyTask {
@Override
void doSomething() {
System.out.println(Thread.currentThread().getName() +" ...." +"say hello...");
}
}
- 第一種消費者模式
每個線程持有一個任務隊列。用消費代理分發給不同的線程處理,詳細如下:
Customer
package com.ricisung.Model.chapter1;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.log4j.Logger;
public class Customer extends Thread {
private static Logger logger = Logger.getLogger(Customer.class);
private BlockingQueue<MyTask> queue = new LinkedBlockingQueue<MyTask>();
public void putTask(MyTask task) throws InterruptedException {
queue.add(task);
}
@Override
public void run() {
while (true) {
try {
MyTask task = queue.take();
task.doSomething();
} catch (Throwable e) {
logger.error("",e);
}
}
}
}
消息代理: 消費者代理,隨機選取一個消費者,進行消費
CustomerProxy :
package com.ricisung.Model.chapter1;
import java.util.Random;
import org.apache.log4j.Logger;
public class CustomerProxy {
private static Logger logger = Logger.getLogger(CustomerProxy.class);
private static CustomerProxy instance = null;
private Customer[] customers = null;
private final int MAX_SIZE = 4;
private CustomerProxy() {
customers = new Customer[MAX_SIZE];
for (int i = 0; i < MAX_SIZE; i++) {
customers[i] = new Customer();
customers[i].setDaemon(true);
customers[i].start();
}
}
public static synchronized CustomerProxy instance() throws InterruptedException {
if (null == instance) {
instance = new CustomerProxy();
}
return instance;
}
public void doWork(MyTask task) {
int index = new Random().nextInt(MAX_SIZE);
try {
customers[index].putTask(task);
} catch (Throwable e) {
logger.error("",e);
}
}
}
- 第二種模式:只有消費代理有一個任務隊列,所有的線程都從消費代理的任務隊列中獲取任務。
CustomerProxy1
package com.ricisung.Model.chapter1;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.log4j.Logger;
public class CustomerProxy1 {
private static Logger logger = Logger.getLogger(CustomerProxy1.class);
private static CustomerProxy1 instance = null;
private Customer1[] customers = null;
private final int MAX_SIZE = 4;
private BlockingQueue<MyTask> queue = new LinkedBlockingQueue<MyTask>();
private CustomerProxy1() {
customers = new Customer1[MAX_SIZE];
for (int i = 0; i < MAX_SIZE; i ++) {
customers[i] = new Customer1();
customers[i].setDaemon(true);
customers[i].start();
}
}
public static synchronized CustomerProxy1 instance() {
if (null == instance) {
instance = new CustomerProxy1();
}
return instance;
}
public void doWork(MyTask task) {
try {
queue.add(task);
} catch (Throwable e) {
logger.error("",e);
}
}
class Customer1 extends Thread {
@Override
public void run() {
while(true) {
try {
MyTask task = queue.take();
task.doSomething();
} catch (Throwable e) {
logger.error("",e);
}
}
}
}
}
Producer 生成者
package com.ricisung.Model.chapter1;
public class Producer {
public static void main(String args[]) throws InterruptedException {
//oneModel();
twoModel();
}
public static void oneModel() throws InterruptedException {
for (int i = 0; i < 100; i ++) {
CustomerProxy.instance().doWork(new SayHelloTask());
}
Thread.sleep(1000 * 5);
}
public static void twoModel() throws InterruptedException {
for (int i = 0; i < 100; i ++) {
CustomerProxy1.instance().doWork(new SayHelloTask());
}
Thread.sleep(1000 * 5);
}
}
測試結果:
兩種模式的比較
兩種默認都可以有效的完成任務。
第一種,每個線程都具有一個自己的任務隊列,這種模式相比第二種模式,CPU減少了在不同線程阻塞,減少了線程排隊同步問題。
第二種,因爲多個線程同時共享了一個隊列,所以這種模式更充分的利用了線程; 第一種模式中一個線程完成任務了,就會立即阻塞,不會幫助其他線程共同完成任務;
如果多種任務同時存在,並且不同任務之間需要按相互先後順序,使用第一種模式就能很好的解決此類問題:將有依賴關係的任務放到同一個線程裏進行處理。
7.源碼下載地址
http://download.csdn.net/detail/jia281460530/9539500