`
zds625
  • 浏览: 10849 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
社区版块
存档分类

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

    博客分类:
  • 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类型后,编译器与运行时会监视这个变量:它是共享的,而且对它的操作不会与其他内存操作一起被重排序。
分享到:
评论
1 楼 zhuorulin 2011-02-28  
重排序。 

相关推荐

Global site tag (gtag.js) - Google Analytics