多线程之synchronized和volatile

来源:互联网 发布:光速网络引擎模块 编辑:程序博客网 时间:2024/05/05 18:24

原子性:指相应的操作是单一不可分割的操作。如:value++就不是原子操作。因为value++可以分解为三个操作(1,读取变量value当前的值;2,那value当前的值做加法运算;3,将运算后的结果赋值给value)


在多线程环境中,非原子性的操作会受到其它线程的干扰。比如上面的例子如果没有进行代码同步(synchronized)处理,则可能出现在执行第二个操作的时候value的值已经被其它线程更改了,因此这个线程所用的value的值其实是一个过期的值。synchronized关键字可以实现操作的原子性。


synchronized关键字可以实现操作的原子性,其本质是通过该关键字所包括的临界区(Critical Section)的排他性保证在任何一个时刻只有一个线程能够执行临界区内的代码。这使临界区中的代码代表了一个原子性操作。


synchronized关键字的另一个作用是保证一个线程执行临界区中的代码时所修改的变量值对于稍后执行该临界区中的代码的线程是可见的。


volatile关键字也能够保证内存的可见性,被该关键字修饰的变量的值的更改对于其他访问该变量的线程是可见的。也就是说,其它线程不会读取到一个过期的值。volatile不能像synchronized所代表的内部锁那样保证操作的原子性。


volatile关键字实现机制:当一个线程修改一个volatile修饰过的变量的值时,该值会被写入主内存(RAM)而不仅仅是当前线程的cpu缓存区,而其它的cpu缓存区中的存储的该变量的值也会因此失效(从而得以更新为主内存中该变量的值)。这就保证了其它线程访问时总是可以获取该变量的最新值。


volatile的另一个作用是它禁止了指令重排序(Re-order)。编译器和cpu为了提高指令的执行效率可能会进行指令重排序,这使得代码的执行方式可能并不是按照我们所认为的方式进行的。如:


private TestObject testObject = new TestObject();


这句代码所做的事情:1,创建类TestObject的实例;2,将类TestObject的实例的引用赋值给变量TestObject。

但由于指令重排序的作用,这段代码的执行顺序可能是:1,分配一段用于存储TestObject实例的内存空间;2,将该内存空间的引用赋值给变量;3,创建TestObject实例。因此,当其它线程访问testObject时有可能得到的仅仅是指向一段存储TestObject实例的内存空间而已。


0 0