Java多线程编程核心技术(第3版)
上QQ阅读APP看书,第一时间看更新

1.12.2 方法suspend()与resume()的缺点——独占

如果suspend()与resume()方法使用不当,极易造成公共同步对象被独占,其他线程无法访问公共同步对象的结果。

创建suspend_resume_deal_lock项目,文件SynchronizedObject.java代码如下:


package testpackage;

public 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");
}

}

文件Run.java代码如下:


package test.run;

import testpackage.SynchronizedObject;

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

}

程序运行结果如图1-55所示。

图1-55 独占并锁死printString()方法

另外一种独占锁的情况也需要格外注意,稍有不注意,就会掉进“坑”里。创建测试项目suspend_resume_LockStop,类MyThread.java代码如下:


package mythread;

public class MyThread extends Thread {
private long i = 0;

@Override
public void run() {
    while (true) {
        i++;
    }
}
}

类Run.java代码如下:


package test.run;

import mythread.MyThread;

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

}

程序运行结果如图1-56所示。

图1-56 控制台输出main end信息

进程状态在控制台中呈红色按钮显示,说明进程并未销毁。虽然main线程销毁了,但是MyThread呈暂停状态,所以进程不会销毁。

如果将线程类MyThread.java更改如下:


package mythread;

public class MyThread extends Thread {
private long i = 0;

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

再次运行程序,则控制台不会输出main end,运行结果如图1-57所示。

图1-57 不输出main end信息

出现这种情况的原因是当程序运行到System.out.println(i)方法内部被暂停时,同步锁是不释放的。println()方法的源代码如图1-58所示。

图1-58 锁不释放

当前PrintStream对象的println()方法一直呈“暂停”状态,并且“锁未释放”,而main()方法中的代码“System.out.println("main end!");”也需要这把锁,main线程并未销毁,导致不能输出“main end!”。

虽然suspend()方法是过期作废的方法,但研究其过期作废的原因还是很有必要的。