为什么i
在Java中不是原子的?
为了更深入地了解Java我试图计算线程中的循环执行的频率。
所以我用了
private static int total = 0;
在主课上。
我有两条线。
系统。出来println(“来自线程1的你好!”)
我计算了线程1和线程2打印的线条。但是线程1的线条和线程2的线条不匹配打印出来的总行数。
下面是我的代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Test {
private static int total = 0;
private static int countT1 = 0;
private static int countT2 = 0;
private boolean run = true;
public Test() {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
newCachedThreadPool.execute(t1);
newCachedThreadPool.execute(t2);
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
run = false;
try {
Thread.sleep(1000);
}
catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println((countT1 + countT2 + " == " + total));
}
private Runnable t1 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT1++;
System.out.println("Hello #" + countT1 + " from Thread 2! Total hello: " + total);
}
}
};
private Runnable t2 = new Runnable() {
@Override
public void run() {
while (run) {
total++;
countT2++;
System.out.println("Hello #" + countT2 + " from Thread 2! Total hello: " + total);
}
}
};
public static void main(String[] args) {
new Test();
}
}
重要的是JLS(Java语言规范),而不是JVM的各种实现如何实现或可能没有实现语言的某个特性。
JLS在第15.14.2条中定义了后缀运算符,其中表示i.a.“将值1添加到变量的值中,并将总和存储回变量中”。它没有提到或暗示多线程或原子性。
对于多线程或原子性,JLS提供了易失性和同步性。此外,还有原子类…
类。
i
涉及两个操作:
i
i
当两个线程同时对同一个变量执行i
时,它们可能都获得相同的当前值i
,然后递增并将其设置为i 1
,因此您将获得单个递增而不是两个。
例:
int i = 5;
Thread 1 : i++;
// reads value 5
Thread 2 : i++;
// reads value 5
Thread 1 : // increments i to 6
Thread 2 : // increments i to 6
// i == 6 instead of 7
i
在Java中可能不是原子性的,因为原子性是一种特殊的要求,在大多数i
的使用中并不存在这种要求。这一要求有很大的开销:使增量操作原子化的成本很高;它涉及软件和硬件层面的同步,而这些不需要在普通增量中出现。
你可以提出这样的论点:i
应该被设计和记录为专门执行原子增量,这样非原子增量就可以使用i=i1
执行。然而,这将打破Java、C和C之间的“文化兼容性”。此外,它还将取消一种方便的符号,而熟悉类似C语言的程序员认为这是理所当然的,这赋予了它一种仅在有限的情况下适用的特殊含义。
基本C或C代码,如(i=0;i)的
即使在机器指令集级别,出于性能原因,增量类型的操作通常也不是原子操作。在x86中,必须使用一条特殊指令“lock prefix”使
inc
指令原子化:原因与上述相同。如果inc
始终是原子的,那么在需要非原子inc时就永远不会使用它;程序员和编译器会生成加载、添加和存储的代码,因为这样会更快。
在一些指令集体系结构中,没有原子
inc
,或者根本没有inc
;要在MIPS上执行原子inc,您必须编写一个软件循环,该循环使用ll
和sc
:load-link和store-条件。Load-link读取单词,如果单词没有更改,则store-条件存储新值,否则将失败(检测到并导致重试)。
问题内容: Java中的原始类型是什么?为什么我经常听到不应该在新代码中使用它们的信息? 如果我们不能使用原始类型,那有什么选择呢?有什么更好的选择? 问题答案: 什么是原始类型? Java语言规范对原始类型的定义如下: JLS 4.8原始类型 原始类型定义为以下之一: 通过采用通用类型声明的名称而没有随附的类型参数列表而形成的引用类型。 数组类型,其元素类型为原始类型。 未从的超类或超接口继承s
问题内容: 什么是决定不具有的接口完全通用的get方法背后的原因。 为了澄清这个问题,方法的签名是 代替 我想知道为什么(与相同)。 问题答案: 正如其他人所提到的,之类的原因不是通用的,因为你要检索的条目的键不必与你传递给的对象的类型相同;方法的规范仅要求它们相等。这从方法如何将对象作为参数(而不仅仅是与对象相同的类型)中得出。 尽管通常已经定义了许多类,以便其对象只能等于其自己的类的对象,这确
本文向大家介绍为什么选择茉莉而不是开玩笑是什么原因?,包括了为什么选择茉莉而不是开玩笑是什么原因?的使用技巧和注意事项,需要的朋友参考一下 没有充分的理由选择茉莉而不是开玩笑。两者都是优秀的库,已经存在了一段时间,并且以一种自以为是的方式来处理非常相似的事情。笑话是建立在茉莉花之上的。 选择茉莉而不是开玩笑的原因之一是它更快。(https://github.com/facebook/jest/is
我与Wildfly和OpenJPA合作。我有一个乐观锁例外的情况。 我得到的错误消息是: 00:08:29373警告[com.arjuna.ats.arjuna](默认任务-39)arjuna01225:TwoPhaseCoordinator。beforeCompletion-SynchronizationImple失败 :org.apache.openjpa.persistence.乐观锁定异常
配置:Windows8英文操作系统;JDK1.7;日食。 我安装了一个中国人写的软件,GUI是汉字。但是软件用方框显示得很难看。我在网上搜索了一下,找到了一个修复它的方法。在Win8的控制面板中,将“非Unicode程序的语言”设置为“中文”。 什么是Java默认字符集?是Unicode吗?Java缺省字符集如何与程序员交互?例如,如果Java使用Unicode,那么字符串“ABC”不能编码到其他
我现在有一个helloworld项目根据这个链接,我做了它的。帽子 文件成功。我有“DE-ABCM_TB”读卡器和SAM卡。 我的小程序AID是 我可以在卡片上选择我的小程序。(我通过"DualCard"发送SELECT APDU命令 2.8版“/pcsc选项卡)。我现在必须在发送时接收十六进制格式的hello 。但我收到6C0B!为什么我会得到这样的回应 我如何解决这个问题?我搜索了一下,但没有