Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 同步简单getter有什么用?_Java_Multithreading_Atomic - Fatal编程技术网

Java 同步简单getter有什么用?

Java 同步简单getter有什么用?,java,multithreading,atomic,Java,Multithreading,Atomic,在Goetz和Co的著名著作《实践中的Java并发性》中,我在一个“好”示例中发现了以下内容: Listing 2.8 @ThreadSafe public class CachedFactorizer implements Servlet { @GuardedBy("this") private BigInteger lastNumber; @GuardedBy("this") private BigInteger[] lastFactors; @GuardedBy("

在Goetz和Co的著名著作《实践中的Java并发性》中,我在一个“好”示例中发现了以下内容:

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);
}

手术?它不是已经是原子的了吗?

最简单的答案是:如果getter没有同步,结果将与没有同步一样


例如,您可以在任何时候调用GETTER,即使另一个线程位于<代码>中的同步< <代码> >块,在Service < /Cult>方法中。另一个不太明显的结果是,getter不能保证在所有的

点击
字段中都观察到任何更新。Java内存模型暗示了这一点,特别是对该字段的写入和getter读取之间没有任何关系。

该变量不是易失的,因此,除非同步访问,否则某些线程可能读取缓存的(可能是过时的)值。实际上,考虑到
hits
计数器不用于决策(即在共享数据结构上写入),而只是用于收集一些统计数据,这不是什么大问题。然而,保护共享变量并确保正确的数据同步是一个很好的实践

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

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

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

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


同步还实现了gd1所说的:它可以帮助运行在一个CPU上的线程所做的更新对运行在其他CPU上的线程可见。Java语言规范规定,无论一个线程在退出
synchronized
块之前内存中发生了什么变化,都必须在另一个线程退出后对另一个线程可见在同一对象上不间断地输入
同步的


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

添加
synchronized
会强制同步缓存的数据交叉线程。如果不存在该变量,则该变量必须是
volatile
。Atomic意味着您无法读取部分更新的值。
++hits
写入一个值,
return hits
因此可以返回一个部分更新的值,如果它没有与
同步。但实际上这很难实现er之所以会发生,是因为Marko在回答中提到的原因,也是因为大多数系统都是64位的。但如果这段代码在32位系统上运行(64位长的值需要两次写入),
getHits()
可能(尽管可能性很小)如果方法不同步太长了,读不下去了,请输入代码。> AtomicLong > <代码> >谢谢。到现在我找到了你的解释。我没有什么反对意见。请你把它变成一个答案吗?,所以,你的论点在64位系统上也很有效。简单的获取在这里不是原子的。@Gangnus看起来像是james large为我做的,他的回答很好地解释了工作中的基本概念和方法。非常感谢,但我在理解上仍然有问题。如果我用getter做一些操作,我可以同步将这些操作的整个块,包括getter,进行初始化。这就足够了,不是吗?根据你的第一个参数,我必须这样做。因此,getter本身的同步似乎过度了…继续…虽然getter将始终用于同步块中,但第二个问题也将得到解决。顺便说一句,对于我来说,bot你的论点似乎是一样的,只是用不同的词表达。当然,问题是我还没有用多线程的术语来思考。你能给你的答案添加一些例子吗?如果getter总是在一个更大的同步块中使用(这个事实在你的问题中并不明显),那么实际上getter不需要自己同步。不过,这不会造成任何影响,因为重新获取一个已经获取的锁实际上是不可操作的(只需增加一个计数器,跟踪同一个锁被获取的次数)你的第二个理由似乎也是一个很好的答案。很抱歉,我不能给出两个答案。这一案例还有一个理由:这不是我的代码,而是戈茨的代码。这本书是12年前写的,当时64位系统是真的
return hits;