Java 使用队列的生产者/消费者线程

Java 使用队列的生产者/消费者线程,java,multithreading,queue,producer-consumer,Java,Multithreading,Queue,Producer Consumer,我想创建一些生产者/消费者线程应用程序。但我不确定在两者之间实现队列的最佳方式是什么 所以我有两个想法(这两个想法可能都是完全错误的)。我想知道哪一个更好,如果它们都很糟糕,那么实现队列的最佳方式是什么。我关心的主要是这些示例中队列的实现。我正在扩展一个队列类,它是内部类,是线程安全的。下面是两个示例,每个示例有4个类 主类- public class SomeApp { private Consumer consumer; private Producer producer;

我想创建一些
生产者/消费者
线程应用程序。但我不确定在两者之间实现队列的最佳方式是什么

所以我有两个想法(这两个想法可能都是完全错误的)。我想知道哪一个更好,如果它们都很糟糕,那么实现队列的最佳方式是什么。我关心的主要是这些示例中队列的实现。我正在扩展一个队列类,它是内部类,是线程安全的。下面是两个示例,每个示例有4个类

主类-

public class SomeApp
{
    private Consumer consumer;
    private Producer producer;

    public static void main (String args[])
    {
        consumer = new Consumer();
        producer = new Producer();
    }
} 
public class SomeApp
{
    Queue<Object> readQ;
    private Consumer consumer;
    private Producer producer;

    public static void main (String args[])
    {
        readQ = new Queue<Object>(100);
        consumer = new Consumer(readQ);
        producer = new Producer(readQ);
    }
} 
消费阶层-

public class Consumer implements Runnable
{
    public Consumer()
    {
        Thread consumer = new Thread(this);
        consumer.start();
    }

    public void run()
    {
        while(true)
        {
            //get an object off the queue
            Object object = QueueHandler.dequeue();
            //do some stuff with the object
        }
    }
}
public class Consumer implements Runnable
{
    Queue<Object> queue;

    public Consumer(Queue<Object> readQ)
    {
        queue = readQ;
        Thread consumer = new Thread(this);
        consumer.start();
    }

    public void run()
    {
        while(true)
        {
            //get an object off the queue
            Object object = queue.dequeue();
            //do some stuff with the object
        }
    }
}
生产者阶级-

public class Producer implements Runnable
{
    public Producer()
    {
        Thread producer = new Thread(this);
        producer.start();
    }

    public void run()
    {
        while(true)
        {
            //add to the queue some sort of unique object
            QueueHandler.enqueue(new Object());
        }
    }
}
public class Producer implements Runnable
{
    Queue<Object> queue;

    public Producer(Queue<Object> readQ)
    {
        queue = readQ;
        Thread producer = new Thread(this);
        producer.start();
    }

    public void run()
    {

        while(true)
        {
            //add to the queue some sort of unique object
            queue.enqueue(new Object());
        }
    }
}
队列类-

public class QueueHandler
{
    //This Queue class is a thread safe (written in house) class
    public static Queue<Object> readQ = new Queue<Object>(100);

    public static void enqueue(Object object)
    {
        //do some stuff
        readQ.add(object);
    }

    public static Object dequeue()
    {
        //do some stuff
        return readQ.get();
    }
}
//the extended Queue class is a thread safe (written in house) class
public class QueueHandler extends Queue<Object>
{    
    public QueueHandler(int size)
    {
        super(size); //All I'm thinking about now is McDonalds.
    }

    public void enqueue(Object object)
    {
        //do some stuff
        readQ.add();
    }

    public Object dequeue()
    {
        //do some stuff
        return readQ.get();
    }
}
公共类队列处理程序
{
//此队列类是线程安全(内部编写)类
公共静态队列readQ=新队列(100);
公共静态void排队(对象)
{
//做点什么
readQ.add(对象);
}
公共静态对象出列()
{
//做点什么
返回readQ.get();
}
}

主类-

public class SomeApp
{
    private Consumer consumer;
    private Producer producer;

    public static void main (String args[])
    {
        consumer = new Consumer();
        producer = new Producer();
    }
} 
public class SomeApp
{
    Queue<Object> readQ;
    private Consumer consumer;
    private Producer producer;

    public static void main (String args[])
    {
        readQ = new Queue<Object>(100);
        consumer = new Consumer(readQ);
        producer = new Producer(readQ);
    }
} 
公共类SomeApp
{
队列读取;
私人消费者;
私营生产者;
公共静态void main(字符串参数[])
{
readQ=新队列(100);
消费者=新消费者(readQ);
生产者=新生产者(readQ);
}
} 
消费阶层-

public class Consumer implements Runnable
{
    public Consumer()
    {
        Thread consumer = new Thread(this);
        consumer.start();
    }

    public void run()
    {
        while(true)
        {
            //get an object off the queue
            Object object = QueueHandler.dequeue();
            //do some stuff with the object
        }
    }
}
public class Consumer implements Runnable
{
    Queue<Object> queue;

    public Consumer(Queue<Object> readQ)
    {
        queue = readQ;
        Thread consumer = new Thread(this);
        consumer.start();
    }

    public void run()
    {
        while(true)
        {
            //get an object off the queue
            Object object = queue.dequeue();
            //do some stuff with the object
        }
    }
}
公共类使用者实现可运行
{
排队;
公共消费者(队列读取)
{
队列=readQ;
线程消费者=新线程(此);
consumer.start();
}
公开募捐
{
while(true)
{
//从队列中获取对象
Object Object=queue.dequeue();
//用这个物体做些东西
}
}
}
生产者阶级-

public class Producer implements Runnable
{
    public Producer()
    {
        Thread producer = new Thread(this);
        producer.start();
    }

    public void run()
    {
        while(true)
        {
            //add to the queue some sort of unique object
            QueueHandler.enqueue(new Object());
        }
    }
}
public class Producer implements Runnable
{
    Queue<Object> queue;

    public Producer(Queue<Object> readQ)
    {
        queue = readQ;
        Thread producer = new Thread(this);
        producer.start();
    }

    public void run()
    {

        while(true)
        {
            //add to the queue some sort of unique object
            queue.enqueue(new Object());
        }
    }
}
公共类生成器实现可运行
{
排队;
公共制作人(队列读取)
{
队列=readQ;
线程生成器=新线程(此线程);
producer.start();
}
公开募捐
{
while(true)
{
//向队列中添加某种独特的对象
排队(新对象());
}
}
}
队列类-

public class QueueHandler
{
    //This Queue class is a thread safe (written in house) class
    public static Queue<Object> readQ = new Queue<Object>(100);

    public static void enqueue(Object object)
    {
        //do some stuff
        readQ.add(object);
    }

    public static Object dequeue()
    {
        //do some stuff
        return readQ.get();
    }
}
//the extended Queue class is a thread safe (written in house) class
public class QueueHandler extends Queue<Object>
{    
    public QueueHandler(int size)
    {
        super(size); //All I'm thinking about now is McDonalds.
    }

    public void enqueue(Object object)
    {
        //do some stuff
        readQ.add();
    }

    public Object dequeue()
    {
        //do some stuff
        return readQ.get();
    }
}
//扩展队列类是线程安全(内部编写)类
公共类QueueHandler扩展了队列
{    
公共队列处理程序(整数大小)
{
超级(大);//我现在想的就是麦当劳。
}
公共无效排队(对象)
{
//做点什么
readQ.add();
}
公共对象出列()
{
//做点什么
返回readQ.get();
}
}

走吧

你正在重新发明轮子。

如果您需要持久性和其他企业特性,请使用(我建议)

如果需要快速内存队列,请使用java的一种实现


如果您需要支持java 1.4或更早版本,请使用Doug Lea的优秀软件包。

java 5+提供了实现这类功能所需的所有工具。您将希望:

  • 把你所有的制作人放在一起
  • 将您的所有消费者放在另一个
    执行器服务中
  • 如有必要,在两人之间使用电话进行通信
  • 我对(3)说“如果必要”,因为根据我的经验,这是一个不必要的步骤。您所要做的就是向consumer executor服务提交新任务。因此:

    final ExecutorService producers = Executors.newFixedThreadPool(100);
    final ExecutorService consumers = Executors.newFixedThreadPool(100);
    while (/* has more work */) {
      producers.submit(...);
    }
    producers.shutdown();
    producers.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    consumers.shutdown();
    consumers.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    

    因此,
    生产者
    直接提交给
    消费者

    好的,正如其他人所指出的,最好使用
    java.util.concurrent
    包。我强烈推荐“实践中的Java并发”。这是一本很棒的书,几乎涵盖了你需要知道的一切

    至于您的特定实现,正如我在评论中指出的,不要从构造函数启动线程——这可能是不安全的

    撇开这一点不谈,第二种实现似乎更好。您不希望将队列放在静态字段中。你可能只是无缘无故地失去了灵活性

    如果您想继续自己的实现(我想是为了学习?),请至少提供一个
    start()
    方法。您应该构造对象(您可以实例化
    线程
    对象),然后调用
    start()
    来启动线程

    编辑:
    ExecutorService
    拥有自己的队列,因此这可能会造成混乱。。这里有一些东西可以让你开始

    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<Runnable>(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();
        }
    }
    
    这样,您可以通过调用
    .shutdownNow()
    关闭执行器。如果您使用
    while(true)
    ,它将不会关闭

    还请注意,
    生产者
    仍然容易受到
    运行时异常
    (即一个
    运行时异常
    将停止处理)

  • Java代码“BlockingQueue”,它具有同步的put和get方法
  • Java代码“Producer”,生成数据的Producer线程
  • Java代码“Consumer”,用于消费线程生成的数据
  • Java代码“ProducerConsumer_Main”,用于启动生产者和消费者线程的主函数
  • BlockingQueue.java

    public class BlockingQueue 
    {
        int item;
        boolean available = false;
    
        public synchronized void put(int value) 
        {
            while (available == true)
            {
                try 
                {
                    wait();
                } catch (InterruptedException e) { 
                } 
            }
    
            item = value;
            available = true;
            notifyAll();
        }
    
        public synchronized int get()
        {
            while(available == false)
            {
                try
                {
                    wait();
                }
                catch(InterruptedException e){
                }
            }
    
            available = false;
            notifyAll();
            return item;
        }
    }
    
    package com.sukanya.producer_Consumer;
    
    public class Consumer extends Thread
    {
        blockingQueue queue;
        private int number;
        Consumer(BlockingQueue queue,int number)
        {
            this.queue = queue;
            this.number = number;
        }
    
        public void run()
        {
            int value = 0;
    
            for (int i = 0; i < 10; i++) 
            {
                value = queue.get();
                System.out.println("Consumer #" + this.number+ " got: " + value);
            }
        }
    }
    
    Consumer.java

    public class BlockingQueue 
    {
        int item;
        boolean available = false;
    
        public synchronized void put(int value) 
        {
            while (available == true)
            {
                try 
                {
                    wait();
                } catch (InterruptedException e) { 
                } 
            }
    
            item = value;
            available = true;
            notifyAll();
        }
    
        public synchronized int get()
        {
            while(available == false)
            {
                try
                {
                    wait();
                }
                catch(InterruptedException e){
                }
            }
    
            available = false;
            notifyAll();
            return item;
        }
    }
    
    package com.sukanya.producer_Consumer;
    
    public class Consumer extends Thread
    {
        blockingQueue queue;
        private int number;
        Consumer(BlockingQueue queue,int number)
        {
            this.queue = queue;
            this.number = number;
        }
    
        public void run()
        {
            int value = 0;
    
            for (int i = 0; i < 10; i++) 
            {
                value = queue.get();
                System.out.println("Consumer #" + this.number+ " got: " + value);
            }
        }
    }
    

    我已经将cletus提出的答案扩展到工作代码示例

  • 一个
    ExecutorService
    (pes)接受
    Producer
    任务
  • 一个
    ExecutorService
    (ces)接受
    消费者
    任务
  • 生产者
    消费者
    共享
    封锁队列
  • 多个
    Producer
    任务生成不同的数字
  • 任何
    消费者
    任务都可以使用
    生产者
  • 代码:


    注意。如果您不需要多个生产者和消费者,请保留单个生产者和消费者。我添加了多个生产者和消费者,以展示在多个生产者和消费者之间阻止队列的功能。

    这是一段非常简单的代码

    import java.util.*;
    
    // @author : rootTraveller, June 2017
    
    class ProducerConsumer {
        public static void main(String[] args) throws Exception {
            Queue<Integer> queue = new LinkedList<>();
            Integer buffer = new Integer(10);  //Important buffer or queue size, change as per need.
    
            Producer producerThread = new Producer(queue, buffer, "PRODUCER");
            Consumer consumerThread = new Consumer(queue, buffer, "CONSUMER");
    
            producerThread.start();  
            consumerThread.start();
        }   
    }
    
    class Producer extends Thread {
        private Queue<Integer> queue;
        private int queueSize ;
    
        public Producer (Queue<Integer> queueIn, int queueSizeIn, String ThreadName){
            super(ThreadName);
            this.queue = queueIn;
            this.queueSize = queueSizeIn;
        }
    
        public void run() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == queueSize){
                        System.out.println(Thread.currentThread().getName() + " FULL         : waiting...\n");
                        try{
                            queue.wait();   //Important
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
    
                    //queue empty then produce one, add and notify  
                    int randomInt = new Random().nextInt(); 
                    System.out.println(Thread.currentThread().getName() + " producing... : " + randomInt); 
                    queue.add(randomInt); 
                    queue.notifyAll();  //Important
                } //synchronized ends here : NOTE
            }
        }
    }
    
    class Consumer extends Thread {
        private Queue<Integer> queue;
        private int queueSize;
    
        public Consumer(Queue<Integer> queueIn, int queueSizeIn, String ThreadName){
            super (ThreadName);
            this.queue = queueIn;
            this.queueSize = queueSizeIn;
        }
    
        public void run() {
            while(true){
                synchronized (queue) {
                    while(queue.isEmpty()){
                        System.out.println(Thread.currentThread().getName() + " Empty        : waiting...\n");
                        try {
                            queue.wait();  //Important
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
    
                    //queue not empty then consume one and notify
                    System.out.println(Thread.currentThread().getName() + " consuming... : " + queue.remove());
                    queue.notifyAll();
                } //synchronized ends here : NOTE
            }
        }
    }
    
    import java.util.*;
    //@author:roottraveler,