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

1.2.10 留意i--与System.out.println()出现的“非线程安全”问题

在前面的章节中,解决非线程安全问题的方法是使用synchronized关键字,本小节将通过程序案例去细化一下println()方法与i--联合使用时“有可能”出现的另外一种异常情况,并说明其产生的原因。

创建名称为sameNum的项目,自定义线程MyThread.java代码如下:


package extthread;

public class MyThread extends Thread {

private int i = 5;

@Override
public void run() {
    System.out.println("i=" + (i--) + " threadName="
        + Thread.currentThread().getName());
    // 注意:代码i--;由单独一行运行
    // 被改成在当前项目中的println()方法中直接进行输出
}

}

运行类Run.java代码如下:


package test;

import extthread.MyThread;

public class Run {

public static void main(String[] args) {

    MyThread run = new MyThread();

    Thread t1 = new Thread(run);
    Thread t2 = new Thread(run);
    Thread t3 = new Thread(run);
    Thread t4 = new Thread(run);
    Thread t5 = new Thread(run);

    t1.start();
    t2.start();
    t3.start();
    t4.start();
    t5.start();

}

}

图1-26 非线程安全问题继续出现

程序运行后还是会出现非线程安全问题,如图1-26所示。

输出i的值有2个4,出现了非线程安全问题。也有一定概率输出2个5。

本实验的测试目的:虽然println()方法在内部是synchronized同步的,但i--操作却是在进入println()之前发生的,所以有一定概率发生非线程安全问题,如图1-27所示。

为了防止发生非线程安全问题,推荐对run()方法继续使用synchronized声明。

图1-27 println()方法在内部是同步的

本例告诉我们:不要看到synchronized就以为代码是安全的,在synchronized之前执行的代码也有可能是不安全的。