首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >同步简单的吸气器有什么用?

同步简单的吸气器有什么用?
EN

Stack Overflow用户
提问于 2015-01-24 15:05:58
回答 3查看 135关注 0票数 2

在Goetz和Co的著名著作“实践中的Java并发”中,在一个“好的”例子中,我发现了以下几点:

代码语言:javascript
复制
Listing 2.8
@ThreadSafe
public class CachedFactorizer implements Servlet {
    @GuardedBy("this") private BigInteger lastNumber;
    @GuardedBy("this") private BigInteger[] lastFactors;
    @GuardedBy("this") private long hits;
    @GuardedBy("this") private long cacheHits;
    public synchronized long getHits() { return hits; } //  <-- here is the problem!
    public synchronized double getCacheHitRatio() {
        return (double) cacheHits / (double) hits;
    }
    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);
        BigInteger[] factors = null;
            synchronized (this) {
                ++hits;
                if (i.equals(lastNumber)) {
                    ++cacheHits;
                    factors = lastFactors.clone();
                }
            }
            if (factors == null) {
            factors = factor(i);
            synchronized (this) {
            lastNumber = i;
            lastFactors = factors.clone();
        }
    }
    encodeIntoResponse(resp, factors);
}

据我所知,这本书的作者说,一个或多个命令可以被同步,如果我们想要它们作为一个片段,一个原子。如果同步段包含多个原子化操作,则它是有意义的。

那么,同步的意义是什么?

代码语言:javascript
复制
return hits;

行动?这不是原子已经了吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-01-24 23:51:46

互斥(即Java synchronized块提供的内容)的主要原因是防止其他线程在一个线程更改数据时看到数据处于不一致的状态。为了使其工作,所有访问数据的线程都必须在同一个对象上同步。修改数据的线程必须是同步的,仅查看数据的线程也必须同步。

您的getHits()方法看起来非常简单,您可能想知道它如何能够看到hits处于不一致的状态,但是hits是一个long。Java规范允许分两个步骤更新long变量,因为在32位硬件上,没有其他方法。因此,如果没有同步,在某些硬件上,getHits()就有可能返回一个从未分配给hits的长值。(也就是说,它可以返回一个64位值,由一个更新中的32位和另一个更新中的32位组成)。

通过同步getHits()方法和更新hits的代码块,您的代码示例可以防止这种情况发生。

同步还可以像gd1所说的那样:它可以帮助运行在一个CPU上的线程进行更新,使在其他CPU上运行的线程可以看到。Java说,无论哪个线程在退出synchronized块之前对内存中的任何变化都必须在另一个线程随后进入同一对象上的synchronized块之后对另一个线程可见。

如果不同步会发生什么,再次取决于硬件平台。在某些系统上,即使没有同步,更新也会很快对其他线程可见,但在其他系统上,复制数据可能需要很长时间。

票数 2
EN

Stack Overflow用户

发布于 2015-01-24 15:15:06

最简单的答案是:如果getter没有同步,结果将是相同的,就好像没有同步一样。

例如,您可以在任何时候调用getter,即使在synchronized块中间的另一个线程位于service方法中。另一个不太明显的后果是,getter将无法在hits字段中观察到任何更新。这是Java内存模型所暗示的,特别是在写到该字段和getter读取之间的关系之前,没有发生任何情况。

票数 5
EN

Stack Overflow用户

发布于 2015-01-24 15:21:06

该变量不是volatile,因此某些线程可以读取缓存的(也可能是过时的)值,除非访问是同步的。实际上,考虑到hits计数器不会用于决策(即编写共享数据结构),而只是为了收集一些统计数据,这并不是什么大事。然而,保护共享变量并确保正确的数据同步是很好的做法。

在这种情况下,使用原子整数可能是一个更好的选择-- IMHO,因为命中次数可以由一些性能监视线程持续采样,并且您只是为了检索一个整数而阻塞整个数据结构。

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

https://stackoverflow.com/questions/28126867

复制
相关文章

相似问题

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