java原语ints是设计的还是偶然的?
就这点而言,java原始整数(int)是原子的吗?对共享int的两个线程进行的一些实验似乎表明它们是,但当然,没有证据表明它们不是,并不意味着它们是 具体来说,我进行的测试是:java原语ints是设计的还是偶然的?,java,multithreading,Java,Multithreading,就这点而言,java原始整数(int)是原子的吗?对共享int的两个线程进行的一些实验似乎表明它们是,但当然,没有证据表明它们不是,并不意味着它们是 具体来说,我进行的测试是: public class IntSafeChecker { static int thing; static boolean keepWatching = true; // Watcher just looks for monotonically increasing values
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();
}
}
公共类IntSafeChecker{
静态整数事物;
静态布尔值keepWatching=true;
//Watcher只是寻找单调递增的值
静态类观察程序扩展线程{
公开募捐{
布尔hasBefore=false;
int thingBefore=0;
同时(继续观察){
//观察共享int
int thingNow=事物;
//伪造第一个值以使测试满意
if(hasBefore==false){
thingBefore=thingNow;
hasBefore=真;
}
//检查是否减少(由于部分写入值)
if(thingNow
(这仅在32位windows PC上使用java jre 1.6.0_07进行了尝试)
本质上,修饰符将一个计数序列写入共享整数,同时观察者检查观察值是否从未减少。在一台32位值必须作为四个独立字节(甚至两个16位字)访问的机器上,观察者很可能会捕获处于不一致、半更新状态的共享整数,并检测到值的减少而不是增加。无论(假设的)数据字节是收集/写入LSB 1st还是写入MSB 1st,这都应该有效,但充其量只是概率性的
考虑到当今广泛的数据路径,32位值很可能是有效的原子值,即使java规范不需要它。事实上,使用32位数据总线,您可能需要比使用32位整数更努力地获得对字节的原子访问
在“java primitive thread safety”(java primitive thread safety)上搜索会发现线程安全类和对象上的大量内容,但查找这些原语的信息似乎是大海捞针。- 再多的测试也不能证明线程的安全性——它只能证明它是错误的李>
- 我发现了一个间接引用,其中
这似乎意味着对int的写入是原子的。这有点复杂,并且与系统字数有关。Bruce Eckel对此进行了更详细的讨论:.默认情况下,Java中的所有内存访问都是原子的,除了
long
和double
(可能是原子的,但不一定是原子的)。老实说,这并没有说得很清楚,但我相信这就是其中的含义
来自JLS的:
在顺序一致的
执行时,有一个总订单已结束
所有单个操作(如读取
并写入)这与
程序的顺序,以及每个
个人行动是原子的,是独立的
每根线都能立即看到
然后在:
一些实现可能会找到它
很方便地分割一次写入
对64位长或双精度文件执行操作
将值转换为上的两个写入操作
相邻的32位值。对于
为了提高效率,这种行为是错误的
具体实施;Java虚拟
机器可以自由地执行写入操作
长值和双值原子或
分为两部分
注意原子性和波动性是非常不同的
当一个线程将一个整数更新为5时,可以保证另一个线程不会看到1、4或任何其他中间状态,但如果没有任何显式的波动性或锁定,另一个线程可能永远看到0
关于努力获得字节的原子访问权,你是对的:虚拟机可能需要努力。。。但这是必须的。从规范的第一部分:
某些处理器不提供
能够写入单个字节。信息技术
实现字节是非法的
在这样的处理器上通过
简单地读一个单词,
更新适当的字节,以及
然后把整个单词写回
记忆。这个问题有时很难解决
被称为单词撕裂,等等
无法轻松更新数据的处理器
孤立的单字节
这需要一种方法
换句话说,由JVM来决定是否正确。从整数或任何较小的类型进行读取或写入应该是原子的,但正如Robert所指出的,long和double可能取决于实现,也可能不取决于实现。但是,任何同时使用读取和写入的操作,包括所有增量运算符,都不是原子操作。因此,如果必须对整数i=0执行操作,一个执行i++操作,另一个执行i=10操作,则结果可能是1、10或11 对于这样的操作,您应该了解在检索旧值时,哪些方法具有原子修改值的方法
private static int i = 0;
public void increment() { i++; }
private static int i = 0;
private static final Object LOCK = new Object();
public void increment() {
synchronized(LOCK) {
i++;
}
}
private static int i = 0;
public static synchronized void increment() {
i++;
}
private static int i = 0;
public void increment() {
synchronized (i) {
i++;
}
}
import java.util.Stack;
public class Test{
static int ctr = Integer.MIN_VALUE;
final static int THREADS = 4;
private static void runone(){
ctr = 0;
Stack<Thread> threads = new Stack<>();
for(int i = 0; i < THREADS; i++){
Thread t = new Thread(new Runnable(){
long cycles = 0;
@Override
public void run(){
while(ctr != Integer.MAX_VALUE){
ctr++;
cycles++;
}
System.out.println("Cycles: " + cycles + ", ctr: " + ctr);
}
});
t.start();
threads.push(t);
}
while(!threads.isEmpty())
try{
threads.pop().join();
}catch(InterruptedException e){
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println();
}
public static void main(String args[]){
System.out.println("Int Range: " + ((long) Integer.MAX_VALUE - (long) Integer.MIN_VALUE));
System.out.println(" Int Max: " + Integer.MAX_VALUE);
System.out.println();
for(;;)
runone();
}
}
Int Range: 4294967295
Int Max: 2147483647
Cycles: 2145700893, ctr: 76261202
Cycles: 2147479716, ctr: 1825148133
Cycles: 2146138184, ctr: 1078605849
Cycles: 2147282173, ctr: 2147483647
Cycles: 2147421893, ctr: 127333260
Cycles: 2146759053, ctr: 220350845
Cycles: 2146742845, ctr: 450438551
Cycles: 2146537691, ctr: 2147483647
Cycles: 2110149932, ctr: 696604594
Cycles: 2146769437, ctr: 2147483647
Cycles: 2147095646, ctr: 2147483647
Cycles: 2147483647, ctr: 2147483647
Cycles: 2147483647, ctr: 330141890
Cycles: 2145029662, ctr: 2147483647
Cycles: 2143136845, ctr: 2147483647
Cycles: 2147007903, ctr: 2147483647
Cycles: 2147483647, ctr: 197621458
Cycles: 2076982910, ctr: 2147483647
Cycles: 2125642094, ctr: 2147483647
Cycles: 2125321197, ctr: 2147483647
Cycles: 2132759837, ctr: 330963474
Cycles: 2102475117, ctr: 2147483647
Cycles: 2147390638, ctr: 2147483647
Cycles: 2147483647, ctr: 2147483647
i++;
i = 5;