线程停止但仍以错误的布尔值(Java)运行

时间:2017-07-16 12:49:32

标签: java multithreading concurrency

所以我写的程序如下:

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;出现,线程停止。为什么呢?

2 个答案:

答案 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
    }