为什么SafePoint类来自实践中的并发书,标记为@ThreadSafe?

时间:2017-02-21 09:54:13

标签: java multithreading concurrency thread-safety

在Java Concurrency in Practice一书中,您可以找到以下代码:

@ThreadSafe
public class SafePoint { 
    @GuardedBy("this") private int x, y;
    private SafePoint(int[] a) { this(a[0], a[1]); }
    public SafePoint(SafePoint p) { this(p.get()); }
    public SafePoint(int x, int y) { 
        this.x = x;
        this.y = y;
    }
    public synchronized int[] get() { return new int[] { x, y };
    }
    public synchronized void set(int x, int y) { this.x = x;
        this.y = y;
    }
}

标记为@ThreadSafe

我很确定这个类不是线程安全的(如果我理解这个术语的话)。

示例:

 SafePoint racePublishedSafePoint; // field

 // thread 1:
 racePublishedSafePoint = new SafePoint(1,1);

 // thread 2:
 SafePoint sp;
 while(true){
   SafePoint sp = racePublishedSafePoint;
   if(sp != null) break;
 }
 System.out.println(sp.get()[0]);
 System.out.println(sp.get()[1]);

我相信有几种可能的结果:

  1. 申请未完成
    否则
  2. 如果申请完成,我们可以看到 a)0 0
    b)0 1
    c)1 0
    d)1 1
  3. 我是对的吗?

    如果为true,为什么作者将该类标记为线程安全?我认为这个线程安全的类 - 可以在没有复杂分析的情况下在并发应用程序中使用。

    作者想说什么?

    P.S。

    我已经读过了 Private constructor to avoid race condition

    ......我的主题不重复。

1 个答案:

答案 0 :(得分:6)

我同意OP,该示例似乎违反了对@ThreadSafe保证的通常理解。不安全的出版物比赛是非常真实的,当然,通过比赛发布SafePoint时,您可以看到令人费解的行为。一些现实生活中的线程安全类可以在有趣的出版物中存活(String是一个臭名昭着的例子),加剧了这种混乱。

就JCIP叙述而言,我没有纸质或电子副本,所以请与Doug Lea(主要作者之一)联系,他说:

  

我认为混淆的部分在JCIP文本中。我不认为   @ThreadSafe涵盖出版比赛,或任何其他可能的比赛   在施工期间遇到。出版物安全得到处理   分开。

     

不过,我可以看到别人怎么想。它是其中之一   我们探索的原因总是放置释放围栏   构造

Doug在谈论的最后一部分在"All Fields Are Final"中进行了简要描述,包括动机,实验补丁和绩效评估。