📜  为什么 JDK 1.1 版本后不推荐使用 Thread.stop()、Thread.suspend() 和 Thread.resume() 方法?

📅  最后修改于: 2022-05-13 01:54:53.809000             🧑  作者: Mango

为什么 JDK 1.1 版本后不推荐使用 Thread.stop()、Thread.suspend() 和 Thread.resume() 方法?

Thread 类包含用于创建和操作线程的构造函数和方法。 Thread 是实现 Runnable 接口的 Object 的子类。线程类中有许多方法,但其中一些方法从 JDK 1.1 开始已被弃用。在本文中,我们将了解其背后的原因。

弃用的方法是那些不再被认为重要且不应使用的方法,因为它们可能会从它们的类中删除。类随着时间的推移而演变,导致它们的 API 发生变化,从而导致弃用。属性发生变化,方法被重命名,并添加了新的方法。为了帮助开发人员从旧 API 转移到新 API,已弃用的类和方法在文档注释中标记为 @deprecated。

为什么弃用??

由于其固有的风险, Thread.stop()正在被淘汰。当您停止一个线程时,它会解锁它锁定的所有监视器。如果以前受这些监视器保护的任何对象处于不一致状态,则其他线程可能会看到这些对象处于不一致状态。
作用在损坏物体上的线程可能有意识或无意识地行为不规律。 ThreadDeath 与其他不受控制的异常不同,它会默默地杀死线程,让用户不会收到程序可能已损坏的警告。损坏发生后,损坏可能会在不可预测的时刻出现。此外,在多线程环境中使用 DBMS – JDBC 时,杀死线程会产生问题。

Thread.suspend()已被弃用,因为它本质上容易死锁。因此,也必须弃用Thread.resume() 。当目标线程被挂起时,它在监视器上持有一个锁来保护一个关键的系统资源,在目标线程恢复之前,没有其他线程可以访问它。如果将重新启动目标线程的线程在调用 resume() 之前尝试锁定此监视器,则会发生死锁。

使用这些不推荐使用的方法可能导致死锁的示例:

Java
// This class contains an integer array &
// Threads set the element's value for this array
class NumVal {
    private int num[] = null;
    boolean valueSet = false;
    int i = 0;
    NumVal()
    {
        // Creating integer array of 10 elements
        num = new int[10];
    }
    // method to set the values in the array
    public void setVal(int n)
    {
        if (i < 9) {
            System.out.println("Putting value " + n
                               + " in the NumVal Array");
            num[i] = n;
            i++;
        }
    }
    // method to get the values from the array
    public int getVal()
    {
        if (i >= 0) {
 
            System.out.println("Giving n = " + num[i]);
            i--;
            return num[i + 1];
        }
        else {
            return -1;
        }
    }
}
// Creating Our Thread Class
class MyThread extends Thread {
 
    // MyThread want mutually exclusive
    // lock on the object
    // referred by: NumObjToSetVal
    NumVal NumObjToSetVal = null;
 
    // Constructor
    public MyThread(String threadName, NumVal numV)
    {
        super(threadName);
        NumObjToSetVal = numV;
    }
 
    public void run()
    {
        // Only 1 thread at a time an access the object
        // referred by : NumObjToSetVal
        synchronized (NumObjToSetVal)
        {
            int n = 0;
            while (n < 5) {
                System.out.println(
                    "THREAD NAME : "
                    + Thread.currentThread().getName());
                n++;
                NumObjToSetVal.setVal(n);
                try {
                    // Make the thread sleep for 100 ms
                    Thread.sleep(100);
                    System.out.println(
                        Thread.currentThread().getName()
                        + "is awake now");
                }
                catch (Exception e) {
                    System.out.println("Exception Caught");
                }
                // If n is 2 , we suspend this thread
                if (n == 2) {
                    // suspend the thread, now this thread
                    // will release lock on NumObjToSetVal
                    // only when resume() method is called
                    // on this thread, thread will go in
                    // waiting state
                    Thread.currentThread().suspend();
                }
            }
        }
    }
}
 
public class Main {
    public static void main(String[] args)
    {
        // TODO Auto-generated method stub
        NumVal v = new NumVal();
 
        // Creating thread 1 that want exclusive lock on
        // object referred by v
        MyThread thread1 = new MyThread("Thread1 ", v);
 
        // Creating thread 2 that want exclusive lock on
        // object referred by v
        // thread1 is not going to release lock on Object
        // referred by v until resume() method is not called
        // and for acquiring lock on v Object refred by v ,
        // thread1 must have released lock on Object
        // referred by v, if lock is not released, thread2
        // will keep on waiting for thread1 to release lock
        // onbject referred by v & deadlock will be formed
        MyThread thread2 = new MyThread("Thread2 ", v);
 
        // starting both threads
        thread1.start();
        thread2.start();
 
        for (int i = 500; i <= 501; i++) {
            System.out.println("Main Thread " + i);
        }
    }
}



输出:

THREAD NAME : Thread1 
Putting value 1 in the NumVal Array
Main Thread 500
Main Thread 501
Thread1 is awake now
THREAD NAME : Thread1 
Putting value 2 in the NumVal Array
Thread1 is awake now
//Deadlock is created & hence no output after this

说明:我们创建了 2 个线程:thread1 和 thread2。两者都希望获得对 'v' 引用所引用的 NumVal 对象的锁定。

当我们通过调用 start() 方法启动两个线程时,只要线程获得 CPU,run() 方法就会执行。线程 1 获取 CPU,当其 run 方法中 n 的值为 2 时,线程被挂起。在调用 resume() 之前,Thread1 不会释放对 'v' 引用的对象的锁定。

要使线程 2 获得对由 'v' 引用的 v 对象的锁,线程 1 必须释放对由 'v' 引用的对象的锁。这里的锁没有被释放,线程 2 将继续等待线程 1 释放对 'v' 引用的对象的锁,从而形成死锁。

因此,每当您在同一线程上调用 suspend() 方法时,您总是(在任何时间)在线程上调用 resume()。