在Java多线程中,i++和i--是非线程安全的。
例子:
public class PlusPlusTest {
public static void main(String[] args) throws InterruptedException {
Num num = new Num();
ThreadA threadA = new ThreadA(num);
ThreadB threadB = new ThreadB(num);
threadA.start();
threadB.start();
Thread.sleep(200);
System.out.println(num.count);
}
}
class ThreadA extends Thread {
private Num num;
public ThreadA(Num num) {
this.num = num;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
num.count++;
}
}
}
class ThreadB extends Thread {
private Num num;
public ThreadB(Num num) {
this.num = num;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
num.count++;
}
}
}
class Num {
int count = 0;
public Num() {
}
}
以上代码输出结果基本上不是2000,会比2000小。
原因:
在线程A中,i++的过程为:
temp1 = i; temp2 = temp1 + 1; i = temp2;
在线程B中,i++的过程为:
temp3 = i; temp4 = temp3 + 1; i = temp4;
在i=0的时候,线程A和B同时读取i=0。
线程A执行++后,i被修改成1。
线程B执行++后,i被修改,但还是1。
问:这样的解释对么?
想到把count变量申明为volatile,但是:
即使把count申明为volatile,输出的结果也不是2000,请问为什么?
class Num {
volatile int count = 0;
public Num() {
}
}
最后
把count变量包装成AtomicInteger之后,输出的结果为2000,正确,这又是为什么?
Because
volatile
不保证操作的原子性,i++
this operation is not an atomic operation.In fact, it is not very appropriate. The operation of
i++
should not be that troublesome. The reading value refers to reading the CPU.An error occurred, the execution sequence is as follows:
线程1
读到i
的值为0
,线程2
也读到i
的值为0
,线程1
执行了+1
操作,将结果值1
Write to memory,线程2
执行了+1
操作,将结果值1
Write to memory.volatile
只能保证可见性,就是说实时读到i
, but atomicity cannot be guaranteed, that is, the above execution sequence is completely allowed to occur. You can also refer to my answer to this question: https://segmentfault.com/q/10...AtomicInteger
是原子的int
,这个是由Java
Implemented, roughly understand the source code:The key point is
compareAndSet()
. This method will determine whether the values ofcurrent
andi
meet the conditions:At this time, whether the value of i It is equal to current
. If the condition is met, exit the loop directly. Otherwise,++
it again until it is normal.compareAndSet()
,这个方法会判断current
与i
的值是否满足条件:此时i的值是否和current相等
,满足条件了直接退出循环,不然再++
一遍,直到正常。compareAndSet方法
是由Java的unsafe
实现的,这个应该很底层了,都是native
方法,我也没研究过。不过,一般程序员是不会接触到unsafe
compareAndSet method
is implemented byJava's unsafe
. This should be very low-level. They are allnative
methods. I have not studied them. However, the average programmer will not be exposed tounsafe
programming.Volatile can only guarantee visibility, that is, you can read it immediately after someone else changes it, but others can also change it when you change it.
AtomicInteger is based on CAS (Compare And Swap).
I am too lazy to write an answer. Here is a very good article: Concurrent Programming in Java: Volatile Keyword Analysis
volatile guarantees that the data obtained each time is the latest (read from memory), i++; --> i=i+1; If it is executed to i+1 without assigning a value to i, there is no guarantee that another thread will get it The data is the latest, and the latter one is an atomic operation, so it can be guaranteed that i = this will definitely be executed