《Java多线程 - 不要同步Boolean常量》测试代码

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=true
Thread-1 - isTrue=false
Thread-0 - Oh, No!
Thread-0 exit
Thread-9 - isTrue=false
Thread-1 - Oh, No!
Thread-1 exit
Thread-9 exit
Thread-8 - isTrue=true
Thread-8 exit
Thread-7 - isTrue=true
Thread-7 exit
Thread-6 - isTrue=true
Thread-6 exit
Thread-5 - isTrue=true
Thread-5 exit
Thread-4 - isTrue=true
Thread-4 exit
Thread-3 - isTrue=true
Thread-3 exit
Thread-2 - isTrue=true
Thread-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:0
Thread-9 aBoolean_costMills:204
Thread-8 aBoolean_costMills:110
Thread-7 aBoolean_costMills:109
Thread-6 anotherBoolean_costMills:110
Thread-5 anotherBoolean_costMills:204
Thread-4 aBoolean_costMills:219
Thread-1 aBoolean_costMills:110
Thread-3 aBoolean_costMills:109
Thread-2 aBoolean_costMills:110

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


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


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值