我有两个线程Producer和Consumer。在objective-c语言中,我使用信号量来阻止和释放线程Consumer。
注意:这与生产者 - 消费者问题有关但不完全。生产者不会等待消费者消费。但消费者将等到生产者生产。消费者并不是在不断阅读。他的阅读只有当制片人告诉他阅读时。并且只读取一些数据。 这里不是共享内存有点。
Thread Consumer{
while(true) {
//Consumer is waiting
dispatch_semaphore_wait(semaphoreVariable, DISPATCH_TIME_FOREVER);
//Copies the data and then goes to wait.
}
}
Thread Producer{
while(true){
//write to buffer
//Continuously writes to buffer. No Waiting.
//After writing Some Blocks asks consumer to consume
dispatch_semaphore_signal(semaPhoreBlock);
}
}
像这样,信号量用于连续阻止和释放消费者线程。
如何在JAVA中实现这种机制?非常感谢任何形式的帮助。
答案 0 :(得分:1)
Java解决方案是:不要使用“低级”概念,例如使用/实现信号量。
相反,请使用Java平台提供的众多抽象之一,例如LinkedBlockingQueue。
这很简单:当你有两个线程时,一个线程将内容推送到队列中;而另一个 reader 线程使用take()
方法来获取内容。
其中:take()
阻止!因此,您无需担心“手动”发送信号。一个线程写道,读者坐下来等待内容变得可用。含义:你做不需要明确地告诉读者“开始阅读” - 发生在隐式的情况下。
从这个意义上讲,真正的答案是研究 Java必须提供的产品,而不是尝试自己构建抽象。关于并发性的Oracle tutorials是一个很好的起点。不要认为您的语言A的解决方案必须以另一种语言以相同的方式“工作”。在Java中,作者在使用BlockingQueue时会不需要向读者发出信号。因此,不要通过强制执行来自另一种语言的概念来使您的生活更加复杂!
答案 1 :(得分:1)
我会用“障碍”解决这个协调问题。
消费者不会持续阅读。当制作人通知他这样做时(通过重置屏障),它只会读取一批作品。
我添加了一些等待生产者(因此如果消费者太慢,队列将不会溢出),但生产者只会等待产生一批工作后,没有消费者准备好消费它。
见下文:
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class BarrierExample {
public static final int BATCH_SIZE = 10;
public static void main(String[] args) throws InterruptedException {
BarrierExample barrierExample = new BarrierExample();
barrierExample.doTheWork();
}
private void doTheWork() throws InterruptedException {
Queue<String> queue = new ConcurrentLinkedQueue();
CyclicBarrier barrier = new CyclicBarrier(2);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new Producer(BATCH_SIZE, queue, barrier));
executorService.submit(new Consumer(BATCH_SIZE, queue, barrier));
Thread.sleep(4000);
System.out.println("main program: trying to shutdown executor service");
executorService.shutdownNow();
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
}
class Producer implements Callable<Void> {
private final int batchSize;
private Queue queue;
private CyclicBarrier barrier;
private Random random = new Random();
public Producer(int batchSize, Queue queue, CyclicBarrier barrier) {
this.batchSize = batchSize;
this.queue = queue;
this.barrier = barrier;
}
@Override
public Void call() {
while (true) {
IntStream.range(1, batchSize).forEach(i -> queue.add(String.valueOf(random.ints(1, 10).findFirst().getAsInt())));
System.out.println("producer: batch size was added to queue.");
while (barrier.getNumberWaiting() < 1) {
try {
System.out.println("producer: nobody is waiting on barrier. going to sleep now");
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (Thread.currentThread().isInterrupted()) {
break;
}
}
System.out.println("producer: consumer was waiting on barrier. reseting the barrier now");
barrier.reset();
if (Thread.currentThread().isInterrupted()) {
System.out.println("producer is ending now!");
break;
}
}
return null;
}
}
class Consumer implements Callable<Void> {
private final int batchSize;
private Queue queue;
private CyclicBarrier barrier;
public Consumer(int batchSize, Queue queue, CyclicBarrier barrier) {
this.batchSize = batchSize;
this.queue = queue;
this.barrier = barrier;
}
@Override
public Void call() {
while (true) {
boolean barrierIsBroken = false;
try {
System.out.println("consumer: waiting on barrier");
barrier.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (BrokenBarrierException e) {
System.out.println("consumer: barrier is broken!!");
barrierIsBroken = true;
}
if (barrierIsBroken) {
System.out.println("consumer: consuming batch");
IntStream.range(1, batchSize).forEach(i -> System.out.println(queue.remove()));
System.out.println("consumer: queue size:" + queue.size());
}
try {
System.out.println("consumer: going to sleep");
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (Thread.currentThread().isInterrupted()) {
System.out.println("consumer is ending now!");
break;
}
}
return null;
}
}