上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之前执行的代码也有可能是不安全的。