我有两个线程,它们都访问Vector。 t1添加一个随机数,而t2删除并打印第一个数字。下面是代码和输出。 t2似乎只执行一次(在t1开始之前)并永远终止。我在这里错过了什么吗? (PS:同样使用ArrayList测试)
import java.util.Random;
import java.util.Vector;
public class Main {
public static Vector<Integer> list1 = new Vector<Integer>();
public static void main(String[] args) throws InterruptedException {
System.out.println("Main started!");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("writer started! ");
Random rand = new Random();
for(int i=0; i<10; i++) {
int x = rand.nextInt(100);
list1.add(x);
System.out.println("writer: " + x);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("reader started! ");
while(!list1.isEmpty()) {
int x = list1.remove(0);
System.out.println("reader: "+x);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
t2.start();
t1.start();
t1.join();
t2.join();
}
} 输出: 主要开始! 读者开始了! 作家开始了! 作家:40 作家:9 作家:23 作家:5 作家:41 作家:29 作家:72 作家:73 作家:95 作家:46
答案 0 :(得分:4)
这听起来像是一个理解并发性的玩具,所以我之前没有提到它,但我现在(因为它很重要,所以在顶部)。
如果这是生产代码,请不要自己动手。 java.util.concurrent中有很多实现良好(调试)的并发数据结构。使用它们。
消费时,您不需要根据&#34;消耗的所有物品&#34;关闭您的消费者。这是由于竞争条件导致消费者可能提前比赛&#34;生产者和检测空列表只是因为生产者还没有写下要消费的物品。
有许多方法可以完成对消费者的关闭,但是没有一种方法可以通过查看要单独使用的数据来完成。
我的建议是制作人&#34;发出信号&#34;生产者完成生产时的消费者。然后,当消费者同时拥有&#34;信号&#34;不再生成数据且列表为空。
替代技术包括创建&#34;关闭&#34;项目。 &#34;制作人&#34;添加关闭项目,而消费者仅在&#34;关闭&#34;项目被看到了。如果您有一组消费者,请记住您不应该删除关闭项目(或者只有一个消费者会关闭)。
此外,消费者可以监控&#34;生产者,如果生产者是&#34;活着/存在&#34;并且列表为空,消费者假定有更多数据可用。当生产者死亡/不存在且没有数据可用时,就会发生关机。
您使用哪种技术取决于您偏好的方法以及您尝试解决的问题。
我知道人们喜欢优雅的解决方案,但如果您的单个制作人知道单个消费者,那么第一个选项就像。
public class Producer {
public void shutdown() {
addRemainingItems();
consumer.shutdown();
}
}
消费者看起来像{
public class Consumer {
private boolean shuttingDown = false;
public void shutdown() {
shuttingDown = true;
}
public void run() {
if (!list.isEmpty() && !shuttingDown) {
// pull item and process
}
}
}
请注意,列表中项目之间缺乏锁定本质上是危险的,但您只说了一个消费者,因此没有争用从列表中读取。
现在,如果您有多个消费者,则需要提供保护以确保单个项目不会被两个线程同时拉出(并且需要以所有线程关闭的方式进行通信)。
答案 1 :(得分:0)
我认为这是典型的Producer–consumer problem。试着看看Semaphore。
答案 2 :(得分:0)
更新:在消费者(读者)中更改while循环后问题消失了。如果列表为空,它现在进入循环但不做任何事情,而不是退出线程。以下是更新的读者线程。当然,也可以在Edwin建议的代码中添加一个不错的关闭机制。
public void run() {
System.out.println("reader started! ");
while(true) {
if(!list1.isEmpty()) {
int x = list1.remove(0);
System.out.println("reader: "+x);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
请注意,这不是从真实产品中获取的代码段,也不会包含在其中!