在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,正确,这又是为什么?
Oleh kerana
volatile
tidak menjamin keatoman operasi,i++
operasi ini bukan operasi atom.sebenarnya tidak begitu sesuai Operasi
i++
tidaklah begitu menyusahkan Nilai bacaan merujuk kepada membaca CPU .Ralat telah berlaku, urutan pelaksanaan adalah seperti berikut:
线程1
membaca bahawa nilaii
ialah0
,线程2
juga membaca bahawa nilaii
ialah0
,线程1
melakukan operasi+1
dan menulis nilai hasil1
ke dalam ingatan,线程2
melaksanakan operasi+1
dan menulis nilai hasil1
ke dalam ingatan.volatile
hanya boleh menjamin keterlihatan, yang bermaksud bahawa nilai terkinii
boleh dibaca dalam masa nyata, tetapi ia tidak dapat menjamin atomicity, iaitu, urutan pelaksanaan di atas dibenarkan sepenuhnya berlaku. Anda juga boleh merujuk kepada jawapan saya untuk soalan ini: https://segmentfault.com/q/10...AtomicInteger
ialah atomint
Ini dilaksanakan olehJava
Mari kita fahami secara kasar kod sumber:Intinya ialah
compareAndSet()
Kaedah ini akan menentukan sama ada nilaicurrent
dani
memenuhi syarat:此时i的值是否和current相等
Jika syarat dipenuhi, keluar terus daripada gelung ,再++
akan diulang sehingga biasa.compareAndSet方法
dilaksanakan olehJava的unsafe
Ini sepatutnya merupakan kaedah yang sangat rendah, dan saya belum mempelajarinya. Walau bagaimanapun, pengaturcara biasa tidak akan didedahkan kepada pengaturcaraannative
.unsafe
Meruap hanya boleh menjamin keterlihatan, iaitu, anda boleh membacanya serta-merta selepas orang lain mengubahnya, tetapi orang lain juga boleh mengubahnya apabila anda menukarnya.
AtomicInteger adalah berdasarkan CAS (Banding Dan Tukar).
Saya terlalu malas untuk menulis jawapan Berikut ialah artikel yang sangat bagus: Pengaturcaraan Serentak dalam Java: Analisis Kata Kunci Meruap
Jaminan yang tidak menentu bahawa data yang diperolehi setiap kali adalah yang terkini (dibaca daripada ingatan), i++ --> i=i+1; Data yang diperolehi oleh benang adalah yang terkini, dan yang terakhir adalah operasi atom, jadi ia boleh dijamin bahawa i = ini pasti akan dilaksanakan