所以我写的程序如下:
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class JustAClass{
private volatile static boolean tof=true;
private static void stop(){
tof=false;
}
private static BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10);
private static void producer() throws InterruptedException{
while(tof){
Random random = new Random();
queue.put(random.nextInt(100));
System.out.println("........");
}
}
private static void consumer() throws InterruptedException{
while(tof){
Random random = new Random();
Thread.sleep(100);
if(random.nextInt(10)==0){
Integer value = queue.take();
System.out.println("Value taken: "+value+"; Queue size: "+queue.size());
}
}
}
public static void main(String[] args) throws InterruptedException{
Scanner scanner = new Scanner(System.in);
System.out.println("Press Enter to terminate");
Thread t1 = new Thread(new Runnable(){
public void run(){
try {
producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable(){
public void run(){
try {
consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
scanner.nextLine();
stop();
t1.join();
t2.join();
System.out.println("Terminated");
}
}
控制台通常会显示:
Press Enter to terminate
........
........
........
........
........
........
........
........
........
........
........
Value taken: 58; Queue size: 10
Value taken: 53; Queue size: 9
........
Value taken: 9; Queue size: 9
........
按Enter键后,程序必须终止。虽然输出停止,但消息&#34;已终止&#34;没有出现。这必须意味着线程必须仍在运行。我哪里做错了? 另外,在某些情况下,消息&#34;终止&#34;出现,线程停止。为什么呢?
答案 0 :(得分:1)
在此添加行
System.out.println(t1.getState()+" "+t2.getState()+" "+queue.size());
t1.join();
t2.join();
你会明白的。生产者正在等待,因为队列大小为10.为了继续,大小必须小于10.因此,有时你的条件
if(random.nextInt(10)==0){
Integer value = queue.take();
System.out.println("Value taken: "+value+"; Queue size: "+queue.size());
}
可能会变为真,它可能会再次进入RUNNING模式。在剩下的时间里,它会一直等待你的主线程。
答案 1 :(得分:1)
此行为是因为BlockingQueue
接口的工作原理。在完成所有线程之前确保已调用drainTo方法,否则BlockingQueue
colud将等待将值返回给不再存在的线程。有关BlockingQueue如何工作的更多信息,请转到BlockingQueue Documentation
可能的解决方案是:转到consumer
方法,在while循环后添加此条件
if (!tof) queue.drainTo(new ArrayList<>());
为了完成程序,这就是conumer方法的样子
private static void consumer() throws InterruptedException{
while(tof){
Random random = new Random();
Thread.sleep(100);
if(random.nextInt(10)==0){
Integer value = queue.take();
System.out.println("Value taken: "+value+"; Queue size: "+queue.size());
}
}
if (!tof) queue.drainTo(new ArrayList<>());
}
希望这有帮助。
备选2:程序等到队列为空。转到使用者方法,转到while条件并验证队列是否为空!queue.isEmpty()
这是备选方案2的样子:
private static void consumer() throws InterruptedException{
while(tof || !queue.isEmpty()){
Random random = new Random();
Thread.sleep(100);
if(random.nextInt(10)==0){
Integer value = queue.take();
System.out.println("Value taken: "+value+"; Queue size: "+queue.size());
}
}
// if (!tof) queue.drainTo(new ArrayList<>()); possible solution 1
}