我开始阅读有关如何安全地停止、中断、挂起和恢复 java 线程的内容,我在 oracle 文档中找到了以下解决方案:
1- 如何安全地停止线程:
private volatile Thread blinker;
public void stop() {
blinker = null;
}
public void run() {
Thread thisThread = Thread.currentThread();
while (blinker == thisThread) {
try {
Thread.sleep(interval);
} catch (InterruptedException e){
}
repaint();
}
}
- 要停止线程,我可以使用 boolean
变量而不是 volatile Thread
,但为什么 Oracle 坚持将 null 影响到启动线?这样做背后有什么 secret (例如,释放使用终结器分配的资源)吗?
2- 如何中断等待很长时间的线程:
public void stop() {
Thread moribund = waiter;
waiter = null;
moribund.interrupt();
}
- 为什么我应该创建新变量 moribund
而不是直接使用 waiter.interrupt()
?
3- 如何暂停和恢复线程:
private volatile boolean threadSuspended;
public void run() {
while (true) {
try {
Thread.sleep(interval);
if (threadSuspended) {
synchronized(this) {
while (threadSuspended)
wait();
}
}
} catch (InterruptedException e){
}
repaint();
}
}
public synchronized void mousePressed(MouseEvent e) {
e.consume();
threadSuspended = !threadSuspended;
if (!threadSuspended)
notify();
}
- 为什么在 run
方法中他们添加了循环 while (threadSuspended)
因为我不明白添加它的目的是什么,并且我的代码可以在没有它的情况下正确编译和运行(具有相同的输出结果)。
来源链接 http://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
最佳答案
1.
使用本地 Thread
变量可防止其他线程调用您对象上的 run()
方法。只有这个对象实例代表的线程才能使用run()
方法。从不同的 Thread
手动调用 Thread
的 run()
方法通常是不好的做法,但肯定有可能。
2.
这一点需要在第1点的上下文中进行解释。这部分还考虑了interval
很长的情况,需要尽快停止线程。
您当然需要使引用无效,否则第 1 部分中的代码将继续循环。但是考虑一下如果将 stop
方法简化为:
public void stop() {
waiter.interrupt();
waiter = null;
}
因为这是从另一个线程执行的,所以它可以以任何方式与 run()
方法交织在一起。例如,threadA调用stop()
停止在run()
中的threadB:
- 线程B: sleep (间隔)
- threadA: waiter.interrupt()
- threadB: 捕获到 InterruptedException
- threadB:调用重绘
- 线程B:进入下一个while循环
- 线程B:进入休眠(间隔)
- threadA: 服务员 == null
在这种情况下,threadB 没有立即停止,而是进行了另一个 sleep 周期,这未能完成 停止等待很长时间的线程
的设置任务。在给定的实现中,您首先取消,然后中断,这可以防止这种行为。
3.
简而言之:因为另一个线程可能已经通知了您的代码,但没有设置正确的标志。 notify()
的一般约定是调用是无害的(但是无用的调用显然会消耗一些资源)。所有线程都应该能够应对虚假唤醒。
关于java - 停止、中断、挂起和恢复 Java 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23795360/