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();
}
}