java - 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();
}
}
我们得到的输出为: Produced
程序挂起。
请帮助提供可能的解决方案/解释
解决方案
使用共享锁。在发布的代码中,每个 Runnable 都将自己用作锁,因此不会发生实际的锁定。
当一个线程等待时,另一个线程需要在同一个锁上调用 notify 以唤醒等待的线程。我们从您的日志中得知 Producer 线程执行其操作,但由于通知作用于与 Consumer 正在使用的锁不同的锁,因此 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
我认为这是你所期待的。
顺便说一句,看看我为队列的简单实现写的另一个答案;你最好保护共享数据结构而不是将代码放在访问数据结构的线程中,特别是看看代码编写有多容易。
推荐阅读
- java - 尝试在 Windows 10 机器上运行时出现 Maven 错误
- java - 考虑到Hashmap,如何在for循环中使用额外的检查?
- r - 即使我不知道唯一值是什么,如何获取数据框列中每个唯一值的计数?
- node.js - Node.js Sequelize 模型,其中一个字段是一组对象
- excel - VBA Excel 清除
- javascript - 如何转义 Javascript 模板字符串的属性?
- express - 如何用 jest 指定运行规范文件的顺序?例如:首先运行 spec.fille1.js 然后 spec.file2.js 等
- python - Pandas:如何在保持空值的同时删除越界时间戳?
- android - 活动结束
- android - Flutter Spotify API 身份验证