《Java多线程

来源:互联网 发布:龙渊网络自由之战 编辑:程序博客网 时间:2024/06/06 01:55

Java多线程 - 不要同步Boolean常量

提出两个观点:

1.Boolean对象赋值为true和false,会改变指向的对象.

测试代码:

private volatile Boolean isTrue = Boolean.FALSE; //此处用false也一样 public void aMethod() {for (int i = 0; i < 10; i++) {Thread t = new Thread() {public void run() {synchronized (isTrue) {isTrue = !isTrue;System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue);try {Double ran = 1000 * Math.random();Thread.sleep(ran.intValue());} catch (InterruptedException e) {}if (!isTrue)System.out.println(Thread.currentThread().getName() + " - Oh, No!");isTrue = !isTrue;System.out.println(Thread.currentThread().getName() + " exit");}}};t.start();}}

其中一次的运行结果:

Thread-0 - isTrue=trueThread-1 - isTrue=falseThread-0 - Oh, No!Thread-0 exitThread-9 - isTrue=falseThread-1 - Oh, No!Thread-1 exitThread-9 exitThread-8 - isTrue=trueThread-8 exitThread-7 - isTrue=trueThread-7 exitThread-6 - isTrue=trueThread-6 exitThread-5 - isTrue=trueThread-5 exitThread-4 - isTrue=trueThread-4 exitThread-3 - isTrue=trueThread-3 exitThread-2 - isTrue=trueThread-2 exit

按照一般的逻辑,isTrue作为共享对象被10个线程共享,每个线程的run方法代码都被isTrue加锁,应该是线程安全的,不应该输出Oh, No!;但是输出结果却刚好相反;

分析原因:isTrue初始化被赋值为Boolean.false这个常量,进入run时,synchronized锁的是Boolean.false这个对象,后取非,isTrue指向发生改变,指向Boolean.true这个常量,后面线程进入run后synchronized锁的Boolean.true这个对象,因此不会发生线程互斥,输出Oh, No!,达不到线程安全目的。


2.以为同步的是不同对象,实际是一个对象。

import java.util.Random;public class BooleanTest {private volatile Boolean aBoolean = false;//Boolean.FALSE;  private volatile Boolean anotherBoolean = false;private long t1 = System.currentTimeMillis();public void aMethod2() {final Random random = new Random();for (int i = 0; i < 10; i++) {Thread t = new Thread() {public void run() {int val = random.nextInt();if (val % 2 == 0) {synchronized (aBoolean) {System.out.println(Thread.currentThread().getName() + " aBoolean_costMills:"+(System.currentTimeMillis() -t1));t1 = System.currentTimeMillis();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}} else {synchronized (anotherBoolean) {System.out.println(Thread.currentThread().getName() + " anotherBoolean_costMills:"+(System.currentTimeMillis() -t1));t1 = System.currentTimeMillis();try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}}};t.start();}}public static void main(String... args) {BooleanTest bt = new BooleanTest();bt.aMethod2();}}
可能的输出:

Thread-0 anotherBoolean_costMills:0Thread-9 aBoolean_costMills:204Thread-8 aBoolean_costMills:110Thread-7 aBoolean_costMills:109Thread-6 anotherBoolean_costMills:110Thread-5 anotherBoolean_costMills:204Thread-4 aBoolean_costMills:219Thread-1 aBoolean_costMills:110Thread-3 aBoolean_costMills:109Thread-2 aBoolean_costMills:110

分析原因:明明程序加了两个锁aBoolean,anotherBoolean,执行这两个锁里面的代码应该是互不干扰,但是打印却显示:如果先前执行的是aBoolean,后面执行的是anotherBoolean,需要等待110ms(正常应该是不等待);如果先前anotherBoolean,后面aBoolean,等待了204ms(正常应该是不等待);这说明这两者执行发生了互斥;原因是aBoolean和anotherBoolean指向了同一对象Boolean.false;其实Boolean.FALSE和false指向的是同一个对象,因此aBoolean赋值Boolean.false还是false,效果一样。


综上:尽量不用使用Boolean对象作为被同步对象,不然可能会出现意想不到的问题,或者对以后的代码修改造成陷阱。


原创粉丝点击