Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java-关于线程中止和死锁的问题-volatile关键字_Java_Multithreading_Deadlock - Fatal编程技术网

java-关于线程中止和死锁的问题-volatile关键字

java-关于线程中止和死锁的问题-volatile关键字,java,multithreading,deadlock,Java,Multithreading,Deadlock,我很难理解如何停止运行的线程。我将试着用例子来解释它。假设以下类别: public class MyThread extends Thread { protected volatile boolean running = true; public void run() { while (running) { synchronized (someObject) { while (someObject.some

我很难理解如何停止运行的线程。我将试着用例子来解释它。假设以下类别:

public class MyThread extends Thread {
    protected volatile boolean running = true;

    public void run() {
        while (running) {
            synchronized (someObject) {
                while (someObject.someCondition() == false && running) {
                    try {
                        someObject.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // do something useful with someObject
            }
        }
    }

    public void halt() {
        running = false;
        interrupt();
    }
}
假设线程正在运行,并且以下语句的计算结果为true:

while (someObject.someCondition() == false && running)
然后,另一个线程调用MyThread.halt()。即使此函数将“running”设置为false(这是一个易失性布尔值)并中断线程,仍会执行以下语句:

someObject.wait();
我们陷入了僵局。线程永远不会停止

然后我想到了这个,但我不确定它是否正确:

public class MyThread extends Thread {
    protected volatile boolean running = true;

    public void run() {
        while (running) {
            synchronized (someObject) {
                while (someObject.someCondition() == false && running) {
                    try {
                        someObject.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                // do something useful with someObject
            }
        }
    }

    public void halt() {
        running = false;
        synchronized(someObject) {
            interrupt();
        }
    }
}
这是正确的吗?这是最常见的方法吗


这似乎是一个显而易见的问题,但我没有找到解决办法。非常感谢您的帮助。

interrupt()调用将在中断的线程中设置一个标志,someObject.wait()将检查该标志,因此您的第一个类应该可以工作。AFAIC第一个是常见的方式,您的错误必须在其他地方。

我尝试模拟第一个版本,事实上,中断标志会被记住。我不知道。下面是我模拟它的代码:

public class Test {
    protected static class MyThread extends Thread {
        protected Object someObject = new Object();

        public void run() {
            for (int i = 0; i < Integer.MAX_VALUE; ++i) {
                /* this takes some time */
            }
            try {
                synchronized (someObject) {
                    someObject.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("WE COME HERE AFTER INTERRUPTED EXCEPTION");
            try {
                synchronized (someObject) {
                    someObject.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("HOWEVER, WE NEVER COME HERE, THE INTERRUPTED FLAG SEEMS TO BE RESETTED");
        }

        public void halt() {
            interrupt();
        }
    }

    public static void main(String[] a) throws InterruptedException {
        MyThread t = new MyThread();
        t.start();
        t.halt();
    }
}
优先于

public void halt() {
    synchronized(someObject) {
        someObject.notifyAll();
    }
}

在这两个版本中,while(…)将再次计算?

中断异常的
捕获
块中,您应该包括:

if (!running)
    break main;
并将您的
while(running)
循环标记为
main:while(running)

调用
中断
无需在
someObject
上同步

另外,我建议您重命名
running
变量,因为它非常混乱。我建议
应该继续
。因此:

public class MyThread extends Thread {
    private volatile boolean shouldContinue = true;

    public void run() {
        main: while (shouldContinue) {
            synchronized (someObject) {
                while (someObject.someCondition() == false && shouldContinue) {
                    try {
                        someObject.wait();
                    } catch (InterruptedException e) {
                        if (!shouldContinue) {
                            break main;
                        }
                    }
                }
                // do something useful with someObject
            }
        }
    }

    public void halt() {
        shouldContinue = false;
        interrupt();
    }
}

或者。。。。您可以使用重载等待方法,该方法将等待的最大毫秒数作为输入。现在,在您的
halt
方法中,您可以只设置
running=false
,rest保证在指定的毫秒之后,等待调用将结束,而while条件将再次得到评估

在下面修改的代码中,等待将阻塞不超过1秒,然后将再次检查while循环条件。这一次,当running设置为false时,循环将结束

synchronized (someObject) {
    while (someObject.someCondition() == false && running) {
        try {
            someObject.wait(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
    }
}
注意:这种方法在高性能线程中可能不是最好的,但我发现它在很多情况下都很有用


顺便说一句-如果JVM执行的逻辑基本上是非阻塞(不可中断)的,比如代码中的while循环条件,那么halt方法触发的中断将“丢失”。您必须依赖“isInterrupted”标志来告诉逻辑是否调用了中断。

第一个版本看起来不错,适合我。也许你已经删掉了你的错误?但是当被打断时,你应该小心地跳过“做一些有用的事情”。跳过这些代码的最佳方法是什么?正在验证“running==true”或“this.isInterrupted()==false”?谢谢,我没有意识到在下一次等待()之前会记住中断标志。我正在处理大量线程。我相信我想尽快阻止它们,而不是任意等待几秒钟。你能详细说明你最后一句话的意思吗?谢谢。如果我将while(someObject.someCondition()==false&&shouldContinue)替换为while(someObject.someCondition()==false),是否仍然正确?@Tiyoal:是的,只要将
shouldContinue
设置为
false
的唯一方法是首先将其设置为
false
,然后调用
中断()
,谢谢,完全如我所料。在这个话题上我学到了很多。谢谢
synchronized (someObject) {
    while (someObject.someCondition() == false && running) {
        try {
            someObject.wait(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
    }
}