[英]Java producer consumer threads
如何實現多個生產者和多個消費者的生產者消費者問題? 我們應該如何創建線程?
創建一個生產者和一個消費者類,這兩個類都
擴展了
實現 Runnable 接口的
Thread 類
,並在需要時調用它們。 你在哪里卡住了?
ConcurrentQueue q = new ConcurrentQueue(100);
ExecutorService service = Executors.newFixedThreadPool(20);
service.execute(new Producer(q));
for (int i=0; i < 18; i++) {
service.execute(new Consumer(q));
}
其中Consumer
和Producer
都是自定義類,它們擴展了 Runnable 並將Queue
作為它們的構造函數參數。
此類通過單個有界阻塞隊列將任意數量的生產者連接到任意數量的消費者。
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public abstract class ProducerConsumer<E> {
private final BlockingQueue<Optional<E>> queue;
public ProducerConsumer(
int numProducerThreads, int numConsumerThreads, int queueCapacity) {
if (numProducerThreads < 1 || numConsumerThreads < 1 || queueCapacity < 1) {
throw new IllegalArgumentException();
}
queue = new ArrayBlockingQueue<Optional<E>>(queueCapacity);
final ExecutorService executor =
Executors.newFixedThreadPool(numProducerThreads + numConsumerThreads);
try {
// Start producer threads
final List<Future<?>> producerFutures = new ArrayList<>();
final AtomicInteger numLiveProducers = new AtomicInteger();
for (int i = 0; i < numProducerThreads; i++) {
producerFutures.add(executor.submit(() -> {
numLiveProducers.incrementAndGet();
// Run producer
producer();
// When last producer finishes, deliver poison pills to consumers
if (numLiveProducers.decrementAndGet() == 0) {
for (int j = 0; j < numConsumerThreads; j++) {
queue.put(Optional.empty());
}
}
return null;
}));
}
// Start consumer threads
final List<Future<?>> consumerFutures = new ArrayList<>();
for (int i = 0; i < numConsumerThreads; i++) {
consumerFutures.add(executor.submit(() -> {
// Run Consumer
consumer();
return null;
}));
}
// Wait for all producers to complete
completionBarrier(producerFutures, false);
// Shut down any consumers that are still running after producers complete
completionBarrier(consumerFutures, false);
} finally {
executor.shutdownNow();
}
}
private static void completionBarrier(List<Future<?>> futures, boolean cancel) {
for (Future<?> future : futures) {
try {
if (cancel) {
future.cancel(true);
}
future.get();
} catch (CancellationException | InterruptedException e) {
// Ignore
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
}
protected void produce(E val) {
try {
queue.put(Optional.of(val));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
protected Optional<E> consume() {
try {
return queue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
/** Producer loop. Call {@link #produce(E)} for each element. */
public abstract void producer();
/**
* Consumer thread. Call {@link #consume()} to get each successive element,
* until an empty {@link Optional} is returned.
*/
public abstract void consumer();
}
使用方法如下:
new ProducerConsumer<Integer>(/* numProducerThreads = */ 1, /* numConsumerThreads = */ 4,
/* queueCapacity = */ 10) {
@Override
public void producer() {
for (int i = 0; i < 100; i++) {
System.out.println("Producing " + i);
produce(i);
}
}
@Override
public void consumer() {
for (Optional<Integer> opt; (opt = consume()).isPresent; ) {
int i = opt.get();
System.out.println("Got " + i);
}
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.