Java 并发之共享对象_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > Java 并发之共享对象

Java 并发之共享对象

 2013/10/8 21:31:00  vivizhyy  程序员俱乐部  我要评论(0)
  • 摘要:上一篇文章说的是,避免多个线程在同一时间访问对象中的同一数据,这篇文章来详细说说共享和发布对象。在没有同步的情况下,我们无法预料编译器、处理器安排操作执行的顺序,经常会发生以为“一定会”发生的动作实际上没有发生。可以用一些简单的方法来避免这个问题。在Java中,如果不是64位版本的,JVM会把double或者long的读和写划分在两个32位中,这样一来,在多线程中,没有声明是volatile的double或者long也是不安全的。锁是同步和互斥的,同样也是内存可见的。为了避免出现读到过期的数据
  • 标签:Java

上一篇文章说的是,避免多个线程在同一时间访问对象中的同一数据,这篇文章来详细说说共享和发布对象。

在没有同步的情况下,我们无法预料编译器、处理器安排操作执行的顺序,经常会发生以为“一定会”发生的动作实际上没有发生。可以用一些简单的方法来避免这个问题。

?

在 Java 中,如果不是64位版本的,JVM 会把 double 或者 long 的读和写划分在两个 32 位中,这样一来,在多线程中,没有声明是 volatile 的 double 或者 long 也是不安全的。

?

锁是同步和互斥的,同样也是内存可见的。为了避免出现读到过期的数据,读和写的线程都要使用公共的锁进行同步。

?

volatile 是一种弱同步,只能保证可见性,而不能保证原子性。(为了安全,可以理解成 volatile 基本上只能使 boolean 的值原子化,像自增这种操作是不能被?volatile?原子化的)在确保?volatile?变量所引用状态的可见性、标识重要的生命周期事件(初始化或者关闭)的时候可以用,其他的时候最好不要用。下面数绵羊的代码就是一种典型的应用:

?

class="java" name="code">volatile boolean asleep;
...
    while(!asleep) {
        count();
    }

如果有其他的线程修改了 asleep, 让它变成 true 了,那么就会跳出循环

?

不要在构造函数中启动线程,有可能造成溢出。用单独的 start() 或者 init() 启动线程

?

对于只在一个线程内使用的数据就没必要同步了,对于可以用 volatile(只有一个线程写入的变量),或者可以用栈限制

?

public in loadTheArk(Collection<Animal> cadidates) {
    SortedSet<Animal> animals;
    int numPairs = 0;
    Animal candidate = null;
    // new 了一个集合来装 cadidates,避免溢出
    animals = new TreeSet<>(new SpeciesGenderComparator());
    animals.addAll(candidates);

    ... // count numPairs
}

?也可以用更规范的方法 ThreadLocal 把线程和持有数值的对象关联在一起。但是这种方法开销比较大。

?

不可变的对象是线程安全的,它必须满足:

  1. 它的状态在创建后不能被修改
  2. 所有的域都是 final 的
  3. 被正确的创建(创建期间没有发生 this 引用的溢出)

?

对象发布时,应该使用同步。但是对于不可变对象来说,可以不用同步。为了安全的发布对象,可以:

  • 静态初始化对象的引用
  • 把它的引用存储到 volatile 域或者 AtomicReference
  • 把它的引用存储到正确创建对象的 final 域中
  • 把它的引用存储到由正确锁保护的域中

?

如果对象本身是可变的,但是发布之后状态不会被修改,那么就在发布的时候对所有线程可见,之后线程访问这个对象就不需要额外的同步了。如果后续状态会被改变,那么必须是线程安全或者锁保护的。

?

?

?

?

?

发表评论
用户名: 匿名