我们知道,long 和 double 赋值在 Java 中不是原子的,除非它们被声明为 volatile。我的问题是它在我们的编程实践中到底有多重要。
例如,如果您看到下面的类,其对象在多个线程之间共享。
/**
* The below class is not thread safe. the assignments to int values would be
* atomic but at the same time it not guaranteed that changes would be visible to
* other threads.
**/
public final class SharedInt {
private int value;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
现在考虑另一个 SharedLong
/**
* The below class is not thread safe because here the assignments to long
* are not atomic as well as changes are not
* guaranteed to be visible to other threads.
*/
public final class SharedLong {
private long value;
public void setValue(long value) {
this.value = value;
}
public long getValue() {
return this.values;
}
}
现在我们可以看到上述两个版本都不是线程安全的。的情况下int
,这是因为线程可能会看到整数的陈旧值。而万一如果long
,他们可以看到 long 变量的损坏和过时的值。
在这两种情况下,如果一个实例是不在多个线程之间共享,那么这些类是安全的.
为了使上述类线程安全,我们需要声明int 和 long 都是易失性的或使方法同步。
这让我想知道:如果分配给long
and double
在我们的正常编程过程中都不是原子的,因为两者都需要声明为易失性或同步以进行多线程访问,所以我的问题是在什么情况下,长赋值不是原子的这一事实可能会产生影响?
我不久前做了一个很酷的小例子
public class UnatomicLong implements Runnable {
private static long test = 0;
private final long val;
public UnatomicLong(long val) {
this.val = val;
}
@Override
public void run() {
while (!Thread.interrupted()) {
test = val;
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new UnatomicLong(-1));
Thread t2 = new Thread(new UnatomicLong(0));
System.out.println(Long.toBinaryString(-1));
System.out.println(pad(Long.toBinaryString(0), 64));
t1.start();
t2.start();
long val;
while ((val = test) == -1 || val == 0) {
}
System.out.println(pad(Long.toBinaryString(val), 64));
System.out.println(val);
t1.interrupt();
t2.interrupt();
}
// prepend 0s to the string to make it the target length
private static String pad(String s, int targetLength) {
int n = targetLength - s.length();
for (int x = 0; x < n; x++) {
s = "0" + s;
}
return s;
}
}
一个线程不断尝试分配0
to test
当另一个尝试分配时-1
。最终你会得到一个数字0b1111111111111111111111111111111100000000000000000000000000000000
or
0b0000000000000000000000000000000011111111111111111111111111111111
.
(假设您使用的不是 64 位 JVM。大多数(如果不是全部)64 位 JVM 实际上都会为long
s and double
s.)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)