我有两个线程都访问一个向量。 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
最佳答案
这听起来像是了解并发性的玩具,所以我之前没有提到它,但是现在我会提到(在顶部,因为它很重要)。
如果这是生产代码,请不要自己动手编写代码。 java.util.concurrent中有很多执行良好(调试)的并发数据结构。使用它们。
消费时,您无需基于“所有消费项目”关闭消费者。这是由于竞争状况造成的,消费者可能会“领先于生产者”并仅由于生产者尚未写出要消费的物品而检测到空列表。
有多种方法可以关闭使用者,但通过孤立地查看要消耗的数据,它们都无法完成。
我的建议是,当生产者完成生产时,生产者“向消费者发出信号”。然后,当消费者同时拥有“信号”和不再生成任何数据且列表为空时,它将停止。
替代技术包括创建“关机”项目。 “生产者”添加了关闭项,而消费者仅在看到“关闭”项时才关闭。如果您有一组使用者,请记住,您不应该删除关机项(否则只有一个使用者会关机)。
同样,消费者可以“监视”生产者,以便如果生产者“活跃/存在”并且列表为空,则消费者会假设会有更多数据可用。当生产者已死/不存在并且无可用数据时,将发生关机。
您使用哪种技术取决于您喜欢的方法和您要解决的问题。
我知道人们喜欢优雅的解决方案,但是如果您的单个生产者知道单个消费者,那么第一个选择就是。
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
}
}
}
请注意,缺少对列表中项目锁定的本质上是危险的,但是您只声明了一个使用者,因此没有争用列表中的内容的争执。
现在,如果您有多个使用者,则需要提供保护以确保单个线程不会同时被两个线程拉出(并且需要以关闭所有线程的方式进行通信)。