简体   繁体   English

Java中的多个消费者生产者

[英]Multiple Consumer Producer In Java

I tried to create 2 threads for consumer and 2 threads for producer. 我试图为消费者创建2个线程,为生产者创建2个线程。 All the 4 threads are racing against one resource. 所有4个线程都在争用一种资源。 Two of them are trying to consume from resource and two of them are trying to produce. 其中两个试图从资源中消费,而两个试图生产。

Below is the code 下面是代码

package com.threading;

import java.util.ArrayList;
import java.util.List;

public class TestConsumerProducer2 {

    protected static int maxSize = 2;

    static class Consumer implements Runnable {
        List<Integer> goods;

        public Consumer(List<Integer> goods) {
            this.goods = goods;
        }

        public void consume() {
            synchronized (goods) {

                if (goods.size() <= 0) {
                    try {
                        goods.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + " >>>> consuming >>>" + goods.remove(0));
                goods.notifyAll();
            }
        }

        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                consume();
                try {
                    Thread.currentThread().sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    static class Producer implements Runnable {
        List<Integer> goods;

        public Producer(List<Integer> goods) {
            this.goods = goods;
        }

        public void produce(int i) {
            synchronized (goods) {

                if (goods.size() >= maxSize) {
                    try {
                        goods.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + ">>> producing >> " + i);
                goods.add(i);
                goods.notifyAll();
            }
        }

        @Override
        public void run() {
            // TODO Auto-generated method stub
            for (int i = 0; i < 10; i++) {
                produce(i);
                try {
                    Thread.currentThread().sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        List<Integer> goods = new ArrayList<>();
        Consumer consumer = new Consumer(goods);
        Producer producer = new Producer(goods);
        Thread consumerWorker1 = new Thread(consumer);
        Thread consumerWorker2 = new Thread(consumer);

        Thread prroducerWorker1 = new Thread(producer);
        Thread prroducerWorker2 = new Thread(producer);

        consumerWorker1.start();
        consumerWorker2.start();
        prroducerWorker1.start();
        prroducerWorker2.start();

        try {
            consumerWorker1.join();
            consumerWorker2.join();
            prroducerWorker1.join();
            prroducerWorker2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("Job completed >>>>");
    }
}

Output Of the program 程序输出

Thread-2>>> producing >> 0 线程2 >>>生产>> 0

Thread-1 >>>> consuming >>>0 线程1 >>>>消耗>>> 0

Thread-3>>> producing >> 0 线程3 >>>生产>> 0

Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:657) at java.util.ArrayList.remove(ArrayList.java:496) at com.threading.TestConsumerProducer2$Consumer.consume(TestConsumerProducer2.java:27) at com.threading.TestConsumerProducer2$Consumer.run(TestConsumerProducer2.java:35) at java.lang.Thread.run(Thread.java:748) Thread-2>>> producing >> 1 线程“ Thread-0”中的异常java.lang.IndexOutOfBoundsException:Index:0,Size:0 at java.util.ArrayList.rangeCheck(ArrayList.java:657)at java.util.ArrayList.remove(ArrayList.java:496) )在com.threading.TestConsumerProducer2 $ Consumer.consume(TestConsumerProducer2.java:27)在com.threading.TestConsumerProducer2 $ Consumer.run(TestConsumerProducer2.java:35)在java.lang.Thread.run(Thread.java:748)线程2 >>>生产>> 1

Thread-1 >>>> consuming >>>0 线程1 >>>>消耗>>> 0

Thread-3>>> producing >> 1 线程3 >>>生产>> 1

Thread-1 >>>> consuming >>>1 线程1 >>>>消耗>>> 1

Thread-2>>> producing >> 2 线程2 >>>生产>> 2

Thread-1 >>>> consuming >>>1 线程1 >>>>消耗>>> 1

Thread-3>>> producing >> 2 线程3 >>>生产>> 2

Thread-1 >>>> consuming >>>2 线程1 >>>>消耗>>> 2

Thread-2>>> producing >> 3 线程2 >>>生产>> 3

Thread-1 >>>> consuming >>>2 线程1 >>>>消耗>>> 2

Thread-2>>> producing >> 4 线程2 >>>生产>> 4

Thread-3>>> producing >> 3 线程3 >>>生产>> 3

Thread-1 >>>> consuming >>>3 线程1 >>>>消耗>>> 3

Thread-2>>> producing >> 5 线程2 >>>生产>> 5

Thread-1 >>>> consuming >>>4 线程1 >>>>消耗>>> 4

Thread-3>>> producing >> 4 线程3 >>>生产>> 4

Thread-1 >>>> consuming >>>3 线程1 >>>>消耗>>> 3

Thread-2>>> producing >> 6 Thread-1 >>>> consuming >>>5 线程2 >>>生产>> 6线程1 >>>>消耗>>> 5

Thread-2>>> producing >> 7 线程2 >>>生产>> 7

Thread-3>>> producing >> 5 线程3 >>>生产>> 5

Problem Statement: Why are none of the threads executing 10 times? 问题陈述:为什么没有一个线程执行10次? Where is the deadlock situation in the code? 代码中的死锁情况在哪里? Why is there an IndexOutOfBoundsException when Goods object is locked by consumer thread and if size <=0 It should go into waiting state? 当商品对象被使用者线程锁定并且size <= 0时,为什么应该进入等待状态,为什么会有IndexOutOfBoundsException?

Changing occurrences of if to while in your code fixes the problem. 更改代码中ifwhile出现可解决此问题。

There is relevant advice in the Guarded Blocks tutorial on Oracle's site where it says: 在Oracle网站上的“ Guarded Blocks”教程中有相关建议:

Note: Always invoke wait inside a loop that tests for the condition being waited for. 注意:始终在循环中调用wait,以测试正在等待的条件。 Don't assume that the interrupt was for the particular condition you were waiting for, or that the condition is still true. 不要以为中断是针对您正在等待的特定条件,还是该条件仍然为真。

(By interrupt they mean return from wait, not necessarily an actual interruption originating from somebody calling Thread.interrupt.) (通过中断,它们表示从等待中返回,而不一定是源自调用Thread.interrupt的人的实际中断。)

Key points: 关键点:

  • A thread knows the contents of the goods list only if it has the lock held at the time that it's checking. 线程仅在检查时拥有锁时才知道商品清单的内容。

  • Calling wait relinquishes the lock, allowing other threads to make progress while this one goes dormant. 调用wait会放弃该锁,从而允许其他线程在此线程处于休眠状态时取得进展。

  • Once a thread relinquishes the lock, any checks it made previously about the state of the goods list are not valid any more. 一旦线程放弃了锁,先前对商品清单状态所做的任何检查将不再有效。

Once a thread returns from wait it has reacquired the lock, but the thread needs to re-evaluate the condition check, otherwise it is acting on stale information. 线程从等待状态返回后,它已经重新获得了锁,但是线程需要重新评估条件检查,否则它将作用于陈旧的信息。 A lot may have happened between the time the thread last checked the condition and the present time. 在线程上次检查条件的时间与当前时间之间可能发生了很多事情。 You get the IllegalArgumentException because the current thread is assuming something is there that another thread removed while the current thread was waiting. 之所以会得到IllegalArgumentException,是因为当前线程假设在等待当前线程时,有另一个线程删除了该线程。

package com.threading;

import java.util.ArrayList; 

import java.util.List;

public class TestConsumerProducer2 {

protected static int maxSize = 2;

static class Consumer implements Runnable {
    List<Integer> goods;

    public Consumer(List<Integer> goods) {
        this.goods = goods;
    }

    public void consume() {
        synchronized (goods) {

            while (goods.size() <= 0) {
                try {
                    goods.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " >>>> consuming >>>" + goods.remove(0));
            goods.notifyAll();
        }
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            consume();
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

static class Producer implements Runnable {
    List<Integer> goods;

    public Producer(List<Integer> goods) {
        this.goods = goods;
    }

    public void produce(int i) {
        synchronized (goods) {

            while (goods.size() >= maxSize) {
                try {
                    goods.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ">>> producing >> " + i);
            goods.add(i);
            goods.notifyAll();
        }
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 10; i++) {
            produce(i);
            try {
                Thread.currentThread().sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

public static void main(String[] args) {
    List<Integer> goods = new ArrayList<>();
    Consumer consumer = new Consumer(goods);
    Producer producer = new Producer(goods);
    Thread consumerWorker1 = new Thread(consumer);
    Thread consumerWorker2 = new Thread(consumer);

    Thread prroducerWorker1 = new Thread(producer);
    Thread prroducerWorker2 = new Thread(producer);

    consumerWorker1.start();
    consumerWorker2.start();
    prroducerWorker1.start();
    prroducerWorker2.start();

    try {
        consumerWorker1.join();
        consumerWorker2.join();
        prroducerWorker1.join();
        prroducerWorker2.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    System.out.println("Job completed >>>>");
}

}

Code now completes successfully, output follows: 代码现在成功完成,输出如下:

C:\>java com.threading.TestConsumerProducer2
Thread-2>>> producing >> 0
Thread-1 >>>> consuming >>>0
Thread-3>>> producing >> 0
Thread-0 >>>> consuming >>>0
Thread-2>>> producing >> 1
Thread-3>>> producing >> 1
Thread-0 >>>> consuming >>>1
Thread-1 >>>> consuming >>>1
Thread-2>>> producing >> 2
Thread-3>>> producing >> 2
Thread-0 >>>> consuming >>>2
Thread-1 >>>> consuming >>>2
Thread-2>>> producing >> 3
Thread-0 >>>> consuming >>>3
Thread-3>>> producing >> 3
Thread-1 >>>> consuming >>>3
Thread-2>>> producing >> 4
Thread-0 >>>> consuming >>>4
Thread-3>>> producing >> 4
Thread-1 >>>> consuming >>>4
Thread-2>>> producing >> 5
Thread-0 >>>> consuming >>>5
Thread-3>>> producing >> 5
Thread-1 >>>> consuming >>>5
Thread-2>>> producing >> 6
Thread-0 >>>> consuming >>>6
Thread-3>>> producing >> 6
Thread-1 >>>> consuming >>>6
Thread-2>>> producing >> 7
Thread-0 >>>> consuming >>>7
Thread-3>>> producing >> 7
Thread-1 >>>> consuming >>>7
Thread-2>>> producing >> 8
Thread-0 >>>> consuming >>>8
Thread-3>>> producing >> 8
Thread-1 >>>> consuming >>>8
Thread-2>>> producing >> 9
Thread-0 >>>> consuming >>>9
Thread-3>>> producing >> 9
Thread-1 >>>> consuming >>>9
Job completed >>>>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM