Java 的 suspend 方法和 resume 方法为何被禁用

① suspend 与 resume 方法极易造成公共的同步对象的独占,使得其他线程无法访问公共同步对象,产生死锁

class Run {
    public static void main(String[] args) {
        try {
            final SynchronizedObject object = new SynchronizedObject();

            Thread thread1 = new Thread() {
                @Override
                public void run() {
                    object.printString();
                }
            };

            thread1.setName("a");
            thread1.start();

            Thread.sleep(1000);

            Thread thread2 = new Thread() {
                @Override
                public void run() {
                    System.out.println("thread2 启动了,但进入不了 printString() 方法!只打印 1 个 begin");
                    System.out.println("因为 printString() 方法被 a 线程锁定并且永远 suspend 暂停了");
                    object.printString();
                }
            };
            thread2.start();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class SynchronizedObject {
    synchronized public void printString() {
        System.out.println("begin");
        if (Thread.currentThread().getName().equals("a")) {
            System.out.println("a 线程永远 suspend 了");
            Thread.currentThread().suspend();
        }
        System.out.println("end");
    }
}

结果:

begin
a 线程永远 suspend 了
thread2 启动了,但进入不了 printString() 方法!只打印 1 个 begin
因为 printString() 方法被 a 线程锁定并且永远 suspend 暂停了

还有另外一种独占锁的情况也需要注意

class Run {
    public static void main(String[] args) {
        try {
            MyThread thread = new MyThread();
            thread.start();
            Thread.sleep(1000);
            thread.suspend();
            System.out.println("main end!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class MyThread extends Thread {
    private long i = 0;

    @Override
    public void run() {
        while (true) {
            i++;
            System.out.println(i);
        }
    }
}

结果:

81171
81172
...

控制台将不打印 main end,出现这样情况的原因是,程序运行到 println() 方法内部停止时,同步锁未被释放。方法 println() 源代码如下:

public void println(long x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

这导致当前 PrintStream 对象的 println() 方法一致呈“暂停”状态,并且“锁未释放”,所以 main() 方法中的代码迟迟不能打印

main 中的 out 对象和 thread 中的 out 对象是同一个,System 中的 out 对象定义是 final static 的:

public final static PrintStream out = null;

② suspend 与 resume 方法容易出现因为线程暂停而导致数据不同步的情况

class MyObject {

    private String username = "1";
    private String password = "11";

    public void setValue(String u, String p) {
        this.username = u;
        if (Thread.currentThread().getName().equals("a")) {
            System.out.println("停止 a 线程");
            Thread.currentThread().suspend();
        }
        this.password = p;
    }

    public void printUsernamePassword() {
        System.out.println(username + " " + password);
    }
}

class Run {

    public static void main(String[] args) throws InterruptedException {
        final MyObject myobject = new MyObject();

        Thread thread1 = new Thread() {
            public void run() {
                myobject.setValue("a", "aa");
            };
        };
        thread1.setName("a");
        thread1.start();

        Thread.sleep(500);

        Thread thread2 = new Thread() {
            public void run() {
                myobject.printUsernamePassword();
            };
        };
        thread2.start();
    }
}

结果:

停止 a 线程
a 11

出现脏读了,因为 suspend() 使得 thread1 暂停,将 CPU 让给 thread2 后,thread2 读取到的是 thread1 没写完的数据

你可能感兴趣的:(Java 的 suspend 方法和 resume 方法为何被禁用)