如何在Java多线程中实现信号量概念?制片人消费者

时间:2017-06-22 06:34:43

标签: java objective-c multithreading semaphore

我有两个线程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中实现这种机制?非常感谢任何形式的帮助。

2 个答案:

答案 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;
    }
}