Java多线程安全的三大特性之可见性

定义

在多线程的程序中,变量不再和单线程一样那么可靠,可以简单地的设置和读取变量的值。这是因为,Java是高级语言,既便是最简单的 i++; 在实际执行的时候,都会因为翻译成底层的机器语言,而变成不止一条语句,而在CPU最终执行的时候,情况还会变得更加复杂。所以,在多线程执行的时候,往往会出现很多意想不到的结果。请看下面的代码:

可见性指的是一个变量对所有的CPU都可见。从物理结构来看,CPU内的每个核心都有自己才可见的缓存空间。为了加快数据操作,系统会将内存中的变量复制一个副本载至核心的私有缓冲上进行处理。这样一来,如果共享内存的数据发生了,副本也必需进行更新,否则则会发生错误。所以可见性,指的就是当一个CPU修改了自己缓冲区的变量数据后,必需通知其他所有的用到此变量的核心。否则就会发生不可见的错误。

案例

在以下示例中,变量 done 同时会被两个线程访问。

class Test extends Thread{
	public boolean done = false;
	
	@Override
	public void run() {
		done = false; 
		try {
			Thread.sleep(100);
		} catch (Exception e) { }  
		done = true; 
		System.out.printf("done = " + done);
	}

	public static void main(String[] args) throws Exception {
		Test t = new Test ();
		t.start(); 
		System.out.printf("等待中……");
		while (!t.done); 
		System.out.printf("完成。");
	} 
}

在 Test 类中,我们定义了一个全局的 boolean 型变量,在 run() 函数中,先设置其为false,然后当所有操作完成时(这里用sleep(100) 来模拟),再设置为 true。我们用这个变量来表示run()是否已经执行完成。因此,在main函数中, 我们使用了while (!t.done) ; 来进行循环等待,直接t.done为true时,才会结束循环,执行下面的打印语句。我们执行了程序,会收到以下结果:

等待中
done = true

我们发现,程序运行后,在控制台中在输出了 done = true 后,而程序仍然处于运行状态。这表明,在主程序的t.done 的状态并没有因此而改变,其值仍然为 false,所以程序卡在这里,无法跳出循环。

在主程序中,定义了一个Test类的对象并启动。然后根据 t.done 判断程序是否结束。最后输出count的值。但是奇怪的是,程序不会输出任何内容,会一直处于“假死”状态。

解决方法一

为字段 done 添加 volatile 关键字,即

public volatile  boolean done = false;

解决方法二

在 main 函数的 while 循环中添加 sleep,即:

		while (!t.done) {
			Thread.sleep(1); 
		}

结论

当一个变量被多个线程访问时,一定要考虑同步的问题。除了以上两种解决办法,Java还提供了更多方法或类。在后的文章中,我们会慢慢看到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值