【java】多线程终止

Java Thread Primitive Deprecation

Why is Thread.stop deprecated?

因为它本质上是不安全。停止线程会使其释放所有已锁定的监视器。(当ThreadDeath异常传播到堆栈时,监视器将被解锁。)如果先前受这些监视器保护的任何对象处于不一致状态,则其他线程现在可能会以不一致的状态查看这些对象。这个时候对象就已经被破坏了。当线程对损坏的对象进行操作时,会产生任意行为。这种行为可能很微妙,难以检测,或者很明显。不同于其他未经检查的异常,ThreadDeath默认杀死线程; 因此,用户没有被警告自己的程序可能被破坏。 程序被破坏的现象可能在实际损害发生后的任何时候,甚至在未来的几个小时或几天内能够体现。

补充:

调用stop()方法时会抛出java.lang.ThreadDeath异常,但在通常的情况下,此异常不需要显式地捕捉。

方法stop()已经被作废,因为如果强制让线程停止则有可能使一些清理性的工作得不到完成。另外一个情况就是对锁定的对象进行了"解锁",导致数据得不到同步的处理,出现数据不一致的问题

Couldn't I just catch the ThreadDeath exception and fix the damaged object?

在理论上是可以的,但它会使多线程代码异常复杂化。但是在实际操作过程中, 这个任务几乎是无法完成的,原因有二:

1.一个线程几乎可以在任何地方抛出一个ThreadDeath异常。 所有同步的方法和块将必须非常详细地研究,提前考虑到这一点。

2.从第一个(在catch或finally子句中)清理一个线程可以抛出第二个ThreadDeath异常。 清理将不得不重复,直到成功。 确保这一点的代码是相当复杂的。

总而言之,这是不实际的。

What about Thread.stop(Throwable)?

In addition to all of the problems noted above, this method may be used to generate exceptions that its target thread is unprepared to handle (including checked exceptions that the thread could not possibly throw, were it not for this method). For example, the following method is behaviorally identical to Java's throw operation, but circumvents the compiler's attempts to guarantee that the calling method has declared all of the checked exceptions that it may throw:

static void sneakyThrow(Throwable t) {

Thread.currentThread().stop(t);

}

What should I use instead of Thread.stop?

大多数停止的使用应该被替换为只是修改一些变量以指示目标线程应该停止运行的代码。 目标线程应该定期检查此变量,如果变量表示要停止运行,则以有序方式从其运行方法返回。 为了确保stop-request的及时通信,变量必须是volatile(或者变量的访问必须同步)

For example, suppose your applet contains the following startstop and run methods:

private Thread blinker;

 

public void start() {

blinker = new Thread(this);

blinker.start();

}

 

public void stop() {

blinker.stop(); // UNSAFE!

}

 

public void run() {

while (true) {

try {

Thread.sleep(interval);

} catch (InterruptedException e){

}

repaint();

}

}

You can avoid the use of Thread.stop by replacing the applet's stop and run methods with:

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

}

}

How do I stop a thread that waits for long periods (e.g., for input)?

上面的处理方式是存在问题的,如果当线程处于非运行状态的时候(当sleep方法被调用或者当wait方法被调用或者被IO阻塞的),上面的方法是不可以使用。此时可以使用interrupt方法来打破阻塞的情况,当interrupt方法来打破阻塞的情况,当interrupt被调用的时候,会抛出InetrruptedException异常,可以通过在run方法中捕获这个异常来让线程安全退出

That's what the Thread.interrupt method is for. The same "state based" signaling mechanism shown above can be used, but the state change (blinker = null, in the previous example) can be followed by a call to Thread.interrupt, to interrupt the wait:

public void stop() {

Thread moribund = waiter;

waiter = null;

moribund.interrupt();

}

For this technique to work, it's critical that any method that catches an interrupt exception and is not prepared to deal with it immediately reasserts the exception. We say reasserts rather than rethrows, because it is not always possible to rethrow the exception. If the method that catches the InterruptedException is not declared to throw this (checked) exception, then it should "reinterrupt itself" with the following incantation:

Thread.currentThread().interrupt();

This ensures that the Thread will reraise the InterruptedException as soon as it is able.

What if a thread doesn't respond to Thread.interrupt?

In some cases, you can use application specific tricks. For example, if a thread is waiting on a known socket, you can close the socket to cause the thread to return immediately. Unfortunately, there really isn't any technique that works in general. It should be noted that in all situations where a waiting thread doesn't respond to Thread.interrupt, it wouldn't respond to Thread.stop either. Such cases include deliberate denial-of-service attacks, and I/O operations for which thread.stop and thread.interrupt do not work properly.

替换方法:也是去触发一个异常,而这个异常与所使用的IO是相关的,例如等待网络信息进入阻塞状态,这个时候可以调用close关闭流,会引发IOException异常,run方法可以通过捕获这个异常来安全结束线程。

Why are Thread.suspend and Thread.resume deprecated?

Thread.suspend is inherently deadlock-prone. If the target thread holds a lock on the monitor protecting a critical system resource when it is suspended, no thread can access this resource until the target thread is resumed. If the thread that would resume the target thread attempts to lock this monitor prior to calling resume, deadlock results. Such deadlocks typically manifest themselves as "frozen" processes.

What should I use instead of Thread.suspend and Thread.resume?

与Thread.stop一样,谨慎的做法是让"目标线程"轮询一个指示线程所需状态(活动或挂起)的变量。 当所需的状态被暂停时,线程将使用Object.wait等待。 当线程恢复时,使用Object.notify通知目标线程。

For example, suppose your applet contains the following mousePressed event handler, which toggles the state of a thread called blinker:

private boolean threadSuspended;

 

Public void mousePressed(MouseEvent e) {

e.consume();

 

if (threadSuspended)

blinker.resume();

else

blinker.suspend(); // DEADLOCK-PRONE!

 

threadSuspended = !threadSuspended;

}

You can avoid the use of Thread.suspend and Thread.resume by replacing the event handler above with:

public synchronized void mousePressed(MouseEvent e) {

e.consume();

 

threadSuspended = !threadSuspended;

 

if (!threadSuspended)

notify();

}

and adding the following code to the "run loop":

synchronized(this) {

while (threadSuspended)

wait();

}

The wait method throws the InterruptedException, so it must be inside a try ... catch clause. It's fine to put it in the same clause as the sleep. The check should follow (rather than precede) the sleep so the window is immediately repainted when the thread is "resumed." The resulting run method follows:

public void run() {

while (true) {

try {

Thread.sleep(interval);

 

synchronized(this) {

while (threadSuspended)

wait();

}

} catch (InterruptedException e){

}

repaint();

}

}

Note that the notify in the mousePressed method and the wait in the run method are inside synchronized blocks. This is required by the language, and ensures that wait and notify are properly serialized. In practical terms, this eliminates race conditions that could cause the "suspended" thread to miss a notify and remain suspended indefinitely.

While the cost of synchronization in Java is decreasing as the platform matures, it will never be free. A simple trick can be used to remove the synchronization that we've added to each iteration of the "run loop." The synchronized block that was added is replaced by a slightly more complex piece of code that enters a synchronized block only if the thread has actually been suspended:

if (threadSuspended) {

synchronized(this) {

while (threadSuspended)

wait();

}

}

In the absence of explicit synchronization, threadSuspended must be made volatile to ensure prompt communication of the suspend-request.

The resulting run method is:

private volatile boolean threadSuspended;

 

public void run() {

while (true) {

try {

Thread.sleep(interval);

 

if (threadSuspended) {

synchronized(this) {

while (threadSuspended)

wait();

}

}

} catch (InterruptedException e){

}

repaint();

}

}

Can I combine the two techniques to produce a thread that may be safely "stopped" or "suspended"?

Yes, it's reasonably straightforward. The one subtlety is that the target thread may already be suspended at the time that another thread tries to stop it. If the stop method merely sets the state variable (blinker) to null, the target thread will remain suspended (waiting on the monitor), rather than exiting gracefully as it should. If the applet is restarted, multiple threads could end up waiting on the monitor at the same time, resulting in erratic behavior.

To rectify this situation, the stop method must ensure that the target thread resumes immediately if it is suspended. Once the target thread resumes, it must recognize immediately that it has been stopped, and exit gracefully. Here's how the resulting run and stop methods look:

public void run() {

Thread thisThread = Thread.currentThread();

while (blinker == thisThread) {

try {

Thread.sleep(interval);

 

synchronized(this) {

while (threadSuspended && blinker==thisThread)

wait();

}

} catch (InterruptedException e){

}

repaint();

}

}

 

public synchronized void stop() {

blinker = null;

notify();

}

If the stop method calls Thread.interrupt, as described above, it needn't call notify as well, but it still must be synchronized. This ensures that the target thread won't miss an interrupt due to a race condition.

What about Thread.destroy?

Thread.destroy was never implemented and has been deprecated. If it were implemented, it would be deadlock-prone in the manner of Thread.suspend. (In fact, it is roughly equivalent to Thread.suspend without the possibility of a subsequent Thread.resume.)

Why is Runtime.runFinalizersOnExit deprecated?

Because it is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock. While this problem could be prevented if the class whose objects are being finalized were coded to "defend against" this call, most programmers do not defend against it. They assume that an object is dead at the time that its finalizer is called.

Further, the call is not "thread-safe" in the sense that it sets a VM-global flag. This forces every class with a finalizer to defend against the finalization of live objects!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值