Producer/Consumer threads using a Queue

前端 未结 7 1813
抹茶落季
抹茶落季 2020-11-22 17:00

I\'d like to create some sort of Producer/Consumer threading app. But I\'m not sure what the best way to implement a queue between the two.

So I\'ve so

7条回答
  •  忘掉有多难
    2020-11-22 17:41

    OK, as others note, the best thing to do is to use java.util.concurrent package. I highly recommend "Java Concurrency in Practice". It's a great book that covers almost everything you need to know.

    As for your particular implementation, as I noted in the comments, don't start Threads from Constructors -- it can be unsafe.

    Leaving that aside, the second implementation seem better. You don't want to put queues in static fields. You are probably just loosing flexibility for nothing.

    If you want to go ahead with your own implementation (for learning purpose I guess?), supply a start() method at least. You should construct the object (you can instantiate the Thread object), and then call start() to start the thread.

    Edit: ExecutorService have their own queue so this can be confusing.. Here's something to get you started.

    public class Main {
        public static void main(String[] args) {
            //The numbers are just silly tune parameters. Refer to the API.
            //The important thing is, we are passing a bounded queue.
            ExecutorService consumer = new ThreadPoolExecutor(1,4,30,TimeUnit.SECONDS,new LinkedBlockingQueue(100));
    
            //No need to bound the queue for this executor.
            //Use utility method instead of the complicated Constructor.
            ExecutorService producer = Executors.newSingleThreadExecutor();
    
            Runnable produce = new Produce(consumer);
            producer.submit(produce);   
        }
    }
    
    class Produce implements Runnable {
        private final ExecutorService consumer;
    
        public Produce(ExecutorService consumer) {
            this.consumer = consumer;
        }
    
        @Override
        public void run() {
            Pancake cake = Pan.cook();
            Runnable consume = new Consume(cake);
            consumer.submit(consume);
        }
    }
    
    class Consume implements Runnable {
        private final Pancake cake;
    
        public Consume(Pancake cake){
            this.cake = cake;
        }
    
        @Override
        public void run() {
            cake.eat();
        }
    }
    

    Further EDIT: For producer, instead of while(true), you can do something like:

    @Override
    public void run(){
        while(!Thread.currentThread().isInterrupted()){
            //do stuff
        }
    }
    

    This way you can shutdown the executor by calling .shutdownNow(). If you'd use while(true), it won't shutdown.

    Also note that the Producer is still vulnerable to RuntimeExceptions (i.e. one RuntimeException will halt the processing)

提交回复
热议问题