首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Brian Goetz: SafePoint示例-它真的是线程安全的吗?

Brian Goetz: SafePoint示例-它真的是线程安全的吗?
EN

Stack Overflow用户
提问于 2015-07-15 18:50:24
回答 3查看 205关注 0票数 1

在Brian Goetz的Java Concurrency In Practice中,有以下示例(清单4.11缩短)。

代码语言:javascript
复制
public class SafePoint {
    private int x, y;
    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;
    }
}

它真的是线程安全的吗?xy既不是volatile也不是final,它们是在没有锁定this的情况下设置的,这意味着调用get()的另一个线程可能会看到陈旧的值(零)。我是不是漏掉了什么?

EN

回答 3

Stack Overflow用户

发布于 2015-07-15 19:00:16

正如synchronized所指出的那样,该方法是线程保存的。至于您的属性xy,在您的示例中,这些属性只在构造函数中编写。因此,您不需要将它们设置为synchronized。如果您为x和/或y实现了某种设置器,则需要将这些设置器设为synchronized,并将属性设为volatile

票数 2
EN

Stack Overflow用户

发布于 2015-07-16 21:59:12

@jameslarge你看过标题了吗?

好的,我在你正在阅读的这本书的索引中查找了“安全发布”,这是3.5.3节中的内容:

正确构造的对象可以通过以下方式安全地发布:从static初始化器初始化对象引用,将对它的引用存储到volatile字段或AtomicReference中,将对它的引用存储到正确构造对象的final字段中,或者将对它的引用存储到由锁正确保护的字段中。

因此,答案取决于如何使用SafePoint类。

如果线程A构造一个SafePoint(5, 15)实例,然后将其存储在非final、非volatile、非static字段中,然后线程B调用safePoint.get();返回给线程B的值可以是[0, 0],也可以是[5, 0][0, 15][5, 15]

如果safePoint字段为finalvolatile,或者它是由静态初始化器设置的static字段,则返回给线程B的值将始终为[5, 15]

这个示例在我的环境中打印result = [5, 15],但是如果我对Goetz先生的书的理解是正确的,那么JLS允许它返回其他三种可能性中的任何一种。

代码语言:javascript
复制
public class SafePointDemo {
SafePoint safePoint;

void threadAwork() {
    safePoint = new SafePoint(5, 15);
    sleep(15000);
}

void threadBwork() {
    sleep(10000);
    int[] result = safePoint.get();
    System.out.println("result = [" + result[0] + ", " + result[1] + "]");
}

private void sleep(long n) {
    try {
    Thread.sleep(n);
    } catch(InterruptedException ex) {
    //do nothing
    }
}

class SafePoint {
    private int x, y;
    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;
    }
}

public static void main(String[] args) {
    SafePointDemo safePointDemo = new SafePointDemo();
    Thread threadA = new Thread(() -> safePointDemo.threadAwork());
    Thread threadB = new Thread(() -> safePointDemo.threadBwork());
    threadA.start();
    threadB.start();
}

}
票数 1
EN

Stack Overflow用户

发布于 2015-07-15 19:00:27

虽然整数不是最终的,但通过在构造函数中只给它们赋值,就可以有效地使它们成为最终的,因为在设置整数之前,指向对象的指针对调用者不可用。

get方法的同步只保证一次只有一个线程能够执行get方法,任何其他线程都将被挂起,直到第一个线程完成。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31428343

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档