Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?

  Thread.stop, Thread.suspend, Thread.resume被标记为废弃的方法。在查看JDK的文档时,提到了下面的参考文章,先是英文版,接着是中文翻译。

  

Why is Thread.stop deprecated?
Because it is inherently unsafe. Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.

Couldn‘t I just catch the ThreadDeath exception and fix the damaged object?
In theory, perhaps, but it would vastly complicate the task of writing correct multithreaded code. The task would be nearly insurmountable for two reasons:

  1. A thread can throw a ThreadDeath exception almost anywhere. All synchronized methods and blocks would have to be studied in great detail, with this in mind.
  2. A thread can throw a second ThreadDeath exception while cleaning up from the first (in the catch or finally clause). Cleanup would have to repeated till it succeeded. The code to ensure this would be quite complex.

In sum, it just isn‘t practical.

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?

Most uses of stop should be replaced by code that simply modifies some variable to indicate that the target thread should stop running. The target thread should check this variable regularly, and return from its run method in an orderly fashion if the variable indicates that it is to stop running. (This is the approach that the Java Tutorial has always recommended.) To ensure prompt communication of the stop-request, the variable must be volatile (or access to the variable must be synchronized).

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

private Thread blinker;

    public void start() {
        blinker = new Thread(this);
        blinker.start();
    }

    public void stop() {
        blinker.stop();  // UNSAFE!
    }

    public void run() {
        Thread thisThread = Thread.currentThread();
        while (true) {
            try {
                thisThread.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 {
                thisThread.sleep(interval);
            } catch (InterruptedException e){
            }
            repaint();
        }
    }

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

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.

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?
As with Thread.stop, the prudent approach is to have the "target thread" poll a variable indicating the desired state of the thread (active or suspended). When the desired state is suspended, the thread waits using Object.wait. When the thread is resumed, the target thread is notified using 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 the thread is "resumed." The resulting run method follows:

public void run() {
        while (true) {
            try {
                Thread.currentThread().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 boolean volatile threadSuspended;

    public void run() {
        while (true) {
            try {
                Thread.currentThread().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 {
                thisThread.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 has never been implemented. 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.) We are not implementing it at this time, but neither are we deprecating it (forestalling its implementation in future). While it would certainly be deadlock prone, it has been argued that there may be circumstances where a program is willing to risk a deadlock rather than exit outright.

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!

下面是中文版翻译:

为什么Thread.stop 被废弃了?

  因为其天生是不安全的。停止一个线程会导致其解锁其上被锁定的所有监视器(监视器以在栈顶产生ThreadDeath异常的方式被解锁)。如果之前被这些监视器保护的任何对象处于不一致状态,其它线程看到的这些对象就会处于不一致状态。这种对象被称为受损的(damaged)。当线程在受损的对象上进行操作时,会导致任意行为。这种行为可能微妙且难以检测, 也可能会比较明显。不像其他未受检的(unchecked)异常,ThreadDeath悄无声息的杀死线程。因此,用户得不到程序可能会崩溃的警告。崩溃会在真正破坏发生后的任意时刻显现,甚至在数小时或数天之后。

难道我不能仅捕获ThreadDeath 异常来修正受损对象吗?

  理论上,也许可以,但书写正确的多线程代码的任务将极其复杂。由于两方面的原因,这一任务的将几乎不可能完成:

  线程可以在几乎任何地方抛出ThreadDeath 异常。由于这一点,所有的同步方法和 (代码)块将必须被考虑得事无巨细。 ? 线程在清理第一个 ThreadDeath 异常的时候(在catch 或finally 语句中),可能会抛出第二个。清理工作将不得不重复直到到其成功。保障这一点的代码将会很复杂。

  Thread.stop(Throwable) 会有什么问题? 除了上述所有问题外,此方法还可能产生其目标线程不准备处理的异常(包括若非为实现此方法,线程不太可能抛出的受检异常)。 例如,下面的方法行为上等同于Java的throw操作,但是绕开了编译器的努力,即保证要调用的方法已经声明了其所有可能抛出的异常:

    static void sneakyThrow(Throwable t) {
        Thread.currentThread().stop(t);
    }

  我应该用什么来取代Thread.stop ? 大多数stop的使用,应当被替换为简单修改某些变量来指示其目标线程将停止运行的代码。 目标线程应当有规律的检查这些变量。并且,如果这些变量指示其将停止运行,目标线程应当以某种有序的方式从它的run方法返回(这正是Java Tutorial一贯建议的方式)。 为了确保停止请求的及时传达,变量必须是 volatile 的(或者变量的访问被同步)。

  例如,假设你的applet包含了start、stop和run方法: 

  private Thread blinker;
    public void start() {
        blinker = new Thread(this);
        blinker.start();
}
    public void stop() {
        blinker.stop();  // UNSAFE!
    }
    public void run() {
        Thread thisThread = Thread.currentThread();
        while (true) {
            try {
                thisThread.sleep(interval);
            } catch (InterruptedException e){
            }
            repaint();
        }
    }  

  为了避免使用Thread.stop ,你可以把applet的stop和run方法替换成:

private volatile Thread blinker;
    public void stop() {
        blinker = null;
    }
    public void run() {
        Thread thisThread = Thread.currentThread(); 

        while (blinker == thisThread) {
            try {
                thisThread.sleep(interval);
            } catch (InterruptedException e){
            }
            repaint();
        }
    }  

  我如何才能停止一个长时间等待的线程(例如,用于输入)?
  这正是Thread.interrupt 方法要做的。
  与上述相同的“基于状态”的信号传递机制可以被应用,但是状态传递(blinker = null ,在上一个例子中)后面可以跟一个Thread.interrupt 调用,用来中断和等待: 

   public void stop() {
        Thread moribund = waiter;
        waiter = null;
        moribund.interrupt();
    }  

  为了让这种技术起作用,关键在于,对于任何捕获了中断异常但不准备立即处理的方法,应重新断言异常。我们说重新断言(reasserts)而不是重新抛出(rethorws),因为要重新抛
出异常并非总是可行。如果捕获InterruptedException 的方法没有被声明为抛出这种(受检)异常,那么它应该采用下述咒语来“重新中断自己”:

Thread.currentThread().interrupt(); 

  如果线程没有响应Thread.interrupt 会怎么样? 在某些情况下,你可以采取特定于应用的技巧。 例如,如果线程在一个已知的socket上等待,你可以关闭这个socket,来促使线程立即返回。不幸的是,确实没有放之四海皆可工作的通用技术。 应当注意,对于等待线程不响应Thread.interrupt的所有情况,它也不会响应Thread.stop 。这些案例包括有意的拒绝服务攻击,以及thread.stop和thread.interrupt不能正常工作的I/O操作。 为什么Thread.suspend 和Thread.resume被废弃了? Thread.suspend 天生容易引起死锁。如果目标线程挂起时在保护系统关键资源的监视器上持有锁,那么其他线程在目标线程恢复之前都无法访问这个资源。 如果要恢复目标线程的线程在调用resume之前试图锁定这个监视器,死锁就发生了 。这种死锁一般自身表现为“冻结(frozen)”进程。

  我应该用什么来取代Thread.suspend 和 Thread.resume ? 与Thread.stop,类似,谨慎的方式,是让“目标线程”轮询一个指示线程期望状态(活动或挂起)的变量。当期望状态是挂起时,线程用Object.wait 来等待;当恢复时,用 Object.notify 来通知目标线程。 (类似生产者消费者) 例如,假设你的applet包含下面的 mousePressed事件句柄,用来切换一个被称为blinker 的线程的状态。 

private boolean threadSuspended;
    Public void mousePressed(MouseEvent e) {
        e.consume();
        if (threadSuspended)
            blinker.resume();
        else
            blinker.suspend();  // DEADLOCK-PRONE!
           threadSuspended = !threadSuspended;
    }  

  要避免使用Thread.suspend和Thread.resume,你可以把上述事件句柄替换为:

public synchronized void mousePressed(MouseEvent e) {
        e.consume();
        threadSuspended = !threadSuspended;
        if (!threadSuspended)
            notify();
    }  

  并把下述代码增加到“运行循环”中:

   synchronized(this) {
                    while (threadSuspended)
                        wait();
                }  

  wait方法抛出InterruptedException,因此他必须在一个“try ... catch”语句中。使用sleep 方法时,也可以将其放入同样的语句中。检查应该在sleep方法后(而不是先于),以便当线程恢复的时候窗口被立即重绘。修改后的run 方法如下:

public void run() {
        while (true) {
            try {
                Thread.currentThread().sleep(interval);
                synchronized(this) {
                    while (threadSuspended)
                        wait();
                }
            } catch (InterruptedException e){
            }
            repaint();
        }
    }  

  注意, mousePressed 方法中的 Notify和run方法中的wait都是在 synchronized语句块中的。这是语言的要求,也确保了wait和 notify 被正确串行化执行。从实际效果来看,这消除了竞争条件,避免了不确定的“挂起”线程丢失notify 消息而仍保持挂起。
  虽然随着平台的成熟Java的同步开销正在减少,但其永远都不会是免费的。有一个简单的技巧,可以用于移除我们加入到“运行循环”每次迭代中的同步。加入的同步块被替换为稍微有点复杂的代码片段,只有当线程真正被挂起的时候后才会进入同步块:

if (threadSuspended) {
                    synchronized(this) {
                        while (threadSuspended)
                             wait();
                    }
                }  

  由于缺少显式同步,threadSuspended 必须被指定为volatile 来保证挂起请求被迅速传递。
  修改后的run 方法如下:‘

private boolean volatile threadSuspended;
    public void run() {
        while (true) {
            try {
                Thread.currentThread().sleep(interval);
                if (threadSuspended) {
                    synchronized(this) {
                        while (threadSuspended)
                            wait();
                    }
                }
            } catch (InterruptedException e){
            }
            repaint();
        }
    }  

  我可以结合两种技术来产生可以安全 “停止”或“挂起”的线程吗?
  是的,这这相当直观。有一个不易察觉的地方,那就是当目标线程可能已经挂起的时候
  另外一个线程试图停止它。
  如果stop方法只是将状态变量(blinker)设置为null,目标线程将仍然处于挂起状态(等待监视器),而不是它所应该的优雅退出。如果applet被重启,多个线程可能会同时结束在monitor上等待,从而导致奇怪的行为。
  为了矫正这种状况,stop方法必须保证挂起的目标线程迅速恢复。一旦目标线程恢复,它必须立即认识到它已经被停止了,并且优雅的退出。这里是修改过的run和stop方法:

public void run() {
        Thread thisThread = Thread.currentThread();
        while (blinker == thisThread) {
            try {
                thisThread.sleep(interval);
                synchronized(this) {
                    while (threadSuspended && blinker==thisThread)
                        wait();
                }
 } catch (InterruptedException e){
            }
            repaint();
        }
    }
     public synchronized void stop() {
        blinker = null;
        notify();
}  

  如果stop方法调用Thread.interrupt ,如前所述,它也不需要调用notify 了,但是他仍然需要被同步。这确保了目标线程不会因竞争条件而丢失中断。
  关于 Thread.destroy 如何呢?
  Thread.destroy 从未被实现。如果它被实现了,它将和Thread.suspend一样易于死锁(事实上,它大致上等同于没有后续Thread.resume 的Thread.suspend )。我们现在既没有实现,也没有废除它(防止将来它被实现)。虽然它确实易于发生死锁,有人争论过,在    有些情况下程序可能愿意冒死锁的险而不是直接退出。

  为什么Runtime.runFinalizersOnExit 被废弃了?
  由于其天生不安全。它可能导致终结器(finallizers)被在活动对象上被调用,而其他
  线程正在并发操作这些对象,导致奇怪的行为或死锁。然而,如果正在被终结对象的类被编码为防御”这种调用,这个问题可以避免。大多数程序员都不会阻止它。它们假设当终结器被调用的时候对象已经死亡。而且,这个调用不是 “线程安全”的,因为它设置了一个VM全局标志。这迫使每个带有终结器的类防御活动对象的终结!

时间: 2024-11-08 19:09:14

Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?的相关文章

PHP5.3中关于VC9和VC6以及Thread Safe和Non Thread Safe版本选择的问题

转自:http://www.htmer.com/article/716.htm 最近在PHP官网上看到又有新版的PHP下载了,于是上去找找For Windows的版本,可是一看确傻眼了,一共给了四个版本,VC9 x86 Non Thread Safe.VC9 x86 Thread Safe.VC6 x86 Non Thread Safe.VC6 x86 Thread Safe,这让我这个菜鸟头疼啊,还好PHP官网提供下载的地方左边有个英文choose我看懂了,我估摸着就是如何来选择版本的意思吧,

Windows下PHP(Thread Safe与Non Thread Safe)版本说明

转载"http://www.taoz11.com/archives/300.html" linux下直接下载源码,在服务器上编译即可,发现windows下有4个版本: VC9 x86 Non Thread SafeVC9 x86 Thread SafeVC6 x86 Non Thread SafeVC6 x86 Thread Safe 网上查看了下4种版本对应使用的情况 一.如何选择 php5.3 的 VC9 版本和 VC6 版本VC6 版本是使用 Visual Studio 6 编译

oracle public redo thread and private redo thread

复习之前的学习内容,对public redo thread 和 private redo thread 的用处还是比较模糊,网上搜集的资料非常有限,看来有些好东西不跳墙是不行的. 废话少说,知识点记录下来: 在rac环境下,每个实例都有自己的redo log,这套redo log称为redo thread.这套概念同样适用于单实例数据库. redo thread有两种,private 和 public ,在默认情况下,我们使用的是public thread.但是如果我们在创建redol log时

Android 判断当前thread 是否是UI thread

在Android 中判断当前的Thread是否是UI Thread 的方法: 1. if (Looper.myLooper() == Looper.getMainLooper()) { // Current thread is the UI/Main thread } 2. if (Looper.getMainLooper().getThread() == Thread.currentThread()) { // Current thread is the UI/Main thread } 参考

【转发】Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on

当您试图从单独的线程更新一个win form时,您将得到如下错误信息: "Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on." 本文将介绍如何处理此错误: 问题: 重现该错误, 添加一个 progress bar 控件 (progressbar1) 以及一个  button(btnStart)到您的

Sub Thread to update main Thread (UI) 2

Sub Thread to update main Thread (UI)  2 Handler.post(somethread); Handler.sendMessage("Msg"); 1 import android.app.Activity; 2 import android.os.Bundle; 3 import android.os.Handler; 4 import android.os.Message; 5 import android.util.Log; 6 impo

Sub Thread to update main Thread (UI)

Sub Thread to update main Thread (UI) main Thread :   A  has Hander.HandleMessage() to process the "Msg" from subthread B; Sub Thread :    B  use  Hander.sendMessage(Msg)  to main Thread A; 1 import java.util.Timer; 2 import java.util.TimerTask;

Java线程中sleep()、wait()和notify()和notifyAll()、suspend和resume()、yield()、join()、interrupt()的用法和区别

从操作系统的角度讲,os会维护一个ready queue(就绪的线程队列).并且在某一时刻cpu只为ready queue中位于队列头部的线程服务. 但是当前正在被服务的线程可能觉得cpu的服务质量不够好,于是提前退出,这就是yield. 或者当前正在被服务的线程需要睡一会,醒来后继续被服务,这就是sleep. sleep方法不推荐使用,可用wait. 线程退出最好自己实现,在运行状态中一直检验一个状态,如果这个状态为真,就一直运行,如果外界更改了这个状态变量,那么线程就停止运行. sleep(

JAVA多线程suspend()、resume()和wait()、notify()的区别(转载)

suspend() 和 resume() 方法:两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的 resume() 被调用,才能使得线程重新进入可执行状态.典型地,suspend() 和 resume() 被用在等待另一个线程产生的结果的情 形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用 resume() 使其恢复.但suspend()方法很容易引起死锁问题, 已经不推荐使用了. wait() 和 notify() 方法:两个方法配