java并发编程实践---共享对象(随笔)

共享和发布对象
synchronized关键字可用于原子操作或者划定“临界区”,还有一个重要的方面:内存可见性,我们希望当一个线程修改了对象状态后,其他的线程能够真正看到改变。而这个可用同步来实现。
可见性
当读线程和写线程分别发生在不同的线程的时候,对于状态的值来说不能确保读线程及时的读取其他线程写入的值。为了确保跨线程写入的内存可见性,必须使用同步机制。
过期数据:一种由于没有恰当使用同步而引起的过期的值。

public class Novisibility {
private static boolean ready;
private static int number;
private static class ReadThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String [] arg) {
new ReadThread().start();
number = 42;
ready = true;
}
}

以上例子在没有同步的情况下运行了两个线程:main方法的主线程和ReadThread线程,从程序上我们认为会输出42,但事实上,它可能输出0,或者根本不会终止。因为没有使用同步不能确保主线程写入ready和number的值对ReadThread线程是可见的。
重排序现象
在单个线程中,只要重排序不会对结果产生影响,那就不保证其中的操作一定按照程序写定的顺序执行---即使重排序对于其他线程来说会产生明显的影响。
在上面的例子,主线程在没有同步的情况下执行,读线程看到的顺序可能与发生写入的顺序正好相反或者完全不同。
所以,只要数据需要被跨线程共享,就需要进行恰当的同步。

非原子的64位操作
过期值确保了线程得到一个真实的数值而不是凭空而来的值,这样的安全保证被称为最低限的安全性,最低限的安全性应用于所有的变量,除了,没有声明为volatile的64位数值变量(double和long),jvm将64位非volatile的double和long变量的读或者写分为两个32位操作,如果读和写发生在不同的线程,那么读取非volatile类型的long和double就可能出现一个值是高32位和另一个值是低32位。因此即使不关心过期值,但在多线程程序中使用共享的、可变的long和double变量也可能是不安全的。除非将它们声明为volatile,或者用锁保护起来。

volatile变量:一种同步的弱形式,确保变量的更新以可预见的方式告诉其他线程,当一个域声明为volatile类型后,编译器与运行时会监视这个变量:它是共享的,而且对它的操作不会与其他内存操作一起被重排序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值