线程生成器java中的消费者

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程生成器java中的消费者相关的知识,希望对你有一定的参考价值。

下面是使用者生产者问题代码,但代码未按预期工作。在这里,消费者和生产者应该只是生产和消费一个对象。

public class ProducerConsumer {
    private static LinkedList<Integer> linkedList = new LinkedList<>();

    public static void main(String a[]) throws InterruptedException {
        Thread producer = new Thread(new Runnable() {

            @Override
            public void run() {
                synchronized(this) {
                    while (linkedList.size() == 1) {
                        try {
                            wait();
                        } catch(InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("Produced");
                    linkedList.add(1);
                    notify();
                    try {
                        Thread.sleep(1000);
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        Thread consume = new Thread(new Runnable() {
            @Override
            public void run() {
                // produce
                synchronized(this) {
                    while (linkedList.isEmpty()) {
                        try {
                            wait();
                        } catch(InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("Consumed");
                    linkedList.removeFirst();
                    notify();
                    try {
                        Thread.sleep(1000);
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        producer.start();
        consume.start();
        producer.join();
        consume.join();

    }
}

我们得到的输出为:生产

程序挂起了。

请帮助解决可能的解决方案/解释

答案

使用共享锁。在发布的代码中,每个Runnable都将自己用作锁,因此不会发生实际的锁定。

当一个线程等待时,另一个线程需要在同一个锁上调用notify以唤醒等待的线程。我们从您的日志记录中知道生产者线程做了它的事情,但由于通知作用于与Consumer正在使用的锁不同的锁,因此消费者线程永远不会醒来。

更改代码以使用共享锁的工作原理:

import java.util.*;

public class ProducerConsumer { private static LinkedList linkedList = new LinkedList();

public static void main(String a[]) throws InterruptedException {
    final Object lock = new Object();
    Thread producer = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (lock) {
                while (linkedList.size() ==1) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Produced");
                linkedList.add(1);
                lock.notify();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });

    Thread consume = new Thread(new Runnable() {
        @Override
        public void run() {
            // produce
            synchronized (lock) {
                while (linkedList.isEmpty()) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Consumed");
                linkedList.removeFirst();
                lock.notify();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    });
    producer.start();
    consume.start();
    producer.join();
    consume.join();

}

}

输出为:

c:example>java ProducerConsumer
Produced
Consumed

我认为这是你所期待的。

顺便说一下,this other answer I wrote可以看到一个简单的队列实现;您最好不要保护共享数据结构,而不是将代码放在访问数据结构的线程中,尤其要看代码编写的容易程度。

另一答案

并发意味着您无法在运行时知道哪个Thread将首先结束。因此,您无法知道哪个消费者和生产者首先被启动,执行或完成。

为了帮助您,您可以使用循环屏障https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html或应用Fork / Join Framework https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html

你的同步集团只是说:一次只有一个线程可以执行这部分代码,而不是执行第一个和第二个代码。

CyclicBarrier的工作原理示例:

service = Executors.newFixedThreadPool(numThreadsTotal);
CyclicBarrier c = new CyclicBarrier(numThreadsToWait);
runProducer();
c.await();
runConsumer();

它将等到执行runProducer以执行runConsumer()的numThreadsT​​oWait一样多的线程。

也许使用大小为1的线程池可以帮助你,但你将失去并发的好处。

另一答案

我认为你能做的最好的就是使用BlockingQueue

以上是关于线程生成器java中的消费者的主要内容,如果未能解决你的问题,请参考以下文章

JAVA 多线程制作大球吃小球 实现球的自动生成及运动 生产消费模型

多线程之Java中的等待唤醒机制

Qt 中的最佳生产者/消费者线程模式

Java 中的多线程你只要看这一篇就够了

java线程同步中没有信号量的生产者消费者问题

Java中的多线程你只要看这一篇就够了