java原始设计或意外原子? [英] Are java primitive ints atomic by design or by accident?

查看:94
本文介绍了java原始设计或意外原子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

原始java原始整数(int)是什么原因?有两个线程共享一个int的实验似乎表明它们,但当然没有证据证明它们并不意味着它们是。

Are java primitive integers (int) atomic at all, for that matter? Some experimentation with two threads sharing an int seems to indicate that they are, but of course absence of evidence that they are not does not imply that they are.

具体来说,我运行的测试是:

Specifically, the test I ran was this:

public class IntSafeChecker {
    static int thing;
    static boolean keepWatching = true;

    // Watcher just looks for monotonically increasing values   
    static class Watcher extends Thread {
        public void run() {
            boolean hasBefore = false;
            int thingBefore = 0;

            while( keepWatching ) {
                // observe the shared int
                int thingNow = thing;
                // fake the 1st value to keep test happy
                if( hasBefore == false ) {
                    thingBefore = thingNow;
                    hasBefore = true;
                }
                // check for decreases (due to partially written values)
                if( thingNow < thingBefore ) {
                    System.err.println("MAJOR TROUBLE!");
                }
                thingBefore = thingNow;
            }
        }
    }

    // Modifier just counts the shared int up to 1 billion
    static class Modifier extends Thread {
        public void run() {
            int what = 0;
            for(int i = 0; i < 1000000000; ++i) {
                what += 1;
                thing = what;
            }
            // kill the watcher when done
            keepWatching = false;
        }
    }

    public static void main(String[] args) {
        Modifier m = new Modifier();
        Watcher w = new Watcher();
        m.start();
        w.start();
    }
}

(这只是尝试使用java jre 1.6。 32位Windows PC上的0_07)

(and that was only tried with java jre 1.6.0_07 on a 32bit windows PC)

本质上,修饰符将计数序列写入共享整数,而观察者检查观察值是否永远不会减少。在必须以四个独立字节(或甚至两个16位字)访问32位值的机器上,观察者有可能在不一致的半更新状态下捕获共享整数,并检测到值减小而不是增加。无论(假设的)数据字节是收集/写入LSB 1st还是MSB 1st,这都应该有效,但最多只能是概率。

Essentially, the Modifier writes a count sequence to the shared integer, while the Watcher checks that the observed values never decrease. On a machine where a 32 bit value had to be accessed as four separate bytes (or even two 16bit words), there would be a probability that Watcher would catch the shared integer in an inconsistent, half-updated state, and detect the value decreasing rather than increasing. This should work whether the (hypothetical) data bytes are collected/written LSB 1st or MSB 1st, but is only probablistic at best.

考虑到今天这个问题很可能即使java规范不需要它,32位值可能是有效原子的数据路径。事实上,使用32位数据总线,您似乎可能需要更加努力地获得字节的原子访问而不是32位整数。

It would seem very probable given today's wide data paths that a 32 bit value could be effectively atomic, even if the java spec doesn't require it. In fact, with a 32 bit data bus it would seem that you might have to work harder to get atomic access to bytes than to 32 bit ints.

谷歌搜索java原始线程安全会在线程安全的类和对象上显示大量内容,但是查找基元的信息似乎是在大海捞针中寻找谚语。

Googling on "java primitive thread safety" turns up loads of stuff on thread-safe classes and objects, but looking for the info on the primitives seems to be looking for the proverbial needle in a haystack.

推荐答案

默认情况下,Java中的所有内存访问都是原子的,但 long 和<$除外c $ c> double (可能是原子的,但不一定是)。说实话并不清楚非常,但我相信这就是含义。

All memory accesses in Java are atomic by default, with the exception of long and double (which may be atomic, but don't have to be). It's not put very clearly to be honest, but I believe that's the implication.

来自第17.4.3节


在顺序一致的
执行中,所有单独操作的总订单超过
(例如读取
和写入)这与程序的顺序
一致,并且每个
单独的动作是原子的,并且每个线程立即可见

Within a sequentially consistent execution, there is a total order over all individual actions (such as reads and writes) which is consistent with the order of the program, and each individual action is atomic and is immediately visible to every thread.

然后在 17.7


有些实现可能会发现
方便划分单个写入
对64位长或双
值的操作,对
相邻的32位值进行两次写操作。为了
效率,这种行为是特定于
的实现; Java虚拟
机器可以自由执行写入
long和double值原子或
分两部分。

Some implementations may find it convenient to divide a single write action on a 64-bit long or double value into two write actions on adjacent 32 bit values. For efficiency's sake, this behavior is implementation specific; Java virtual machines are free to perform writes to long and double values atomically or in two parts.

请注意,原子性与波动性非常不同。

Note that atomicity is very different to volatility though.

当一个线程将整数更新为5时,保证另一个线程不会看到1或4或者任何其他中间状态,但没有任何明显的波动或锁定,另一个线程可以永远看到0。

When one thread updates an integer to 5, it's guaranteed that another thread won't see 1 or 4 or any other in-between state, but without any explicit volatility or locking, the other thread could see 0 forever.

关于努力获得对字节的原子访问你是对的:VM可能不得不努力......但确实如此。来自第17.6节的spec:

With regard to working hard to get atomic access to bytes, you're right: the VM may well have to try hard... but it does have to. From section 17.6 of the spec:


某些处理器不提供写入单个字节的
能力。
在这样的处理器上通过
实现字节
数组更新是非法的,只需读取整个单词,
更新相应的字节,
然后写入整个回到
内存。这个问题有时是
,称为单词撕裂,而在
处理器上,无法轻易更新
单字节,需要一些其他的
方法。

Some processors do not provide the ability to write to a single byte. It would be illegal to implement byte array updates on such a processor by simply reading an entire word, updating the appropriate byte, and then writing the entire word back to memory. This problem is sometimes known as word tearing, and on processors that cannot easily update a single byte in isolation some other approach will be required.

换句话说,由JVM决定是否正确。

In other words, it's up to the JVM to get it right.

这篇关于java原始设计或意外原子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆