今天在iteye上提了一個關于++操作和線程安全的問題,一位朋友的回答一言點醒夢中人,至此我對Java線程鎖有了更加深刻的認識。在這里也做個總結供大家參考
托福代考 托福答案
先看幾段代碼吧!
代碼一:
[java]
public class TestMultiThread2 implements Runnable{
private static Object o = new Object();
private static Integer si = 0;
private static AtomicInteger flag = new AtomicInteger();
@Override
public void run() {
for(int k=0;k<2000000;k++){
synchronized(si){
si++;
}
}
flag.incrementAndGet();
}
public static void main(String[] args) throws InterruptedException{
TestMultiThread2 t1 = new TestMultiThread2();
TestMultiThread2 t2 = new TestMultiThread2();
ExecutorService exec1 = Executors.newCachedThreadPool();
ExecutorService exec2 = Executors.newCachedThreadPool();
exec1.execute(t1);
exec2.execute(t2);
while(true){
if(flag.intValue()==2){
System.out.println("si>>>>>"+si);
break;
}
Thread.sleep(50);
}
}
}
為了方便看,重復的就不插入了,從代碼二到代碼四只插入run()方法中的代碼,其他地方都一樣
代碼二:
[java]
public void run() {
for(int k=0;k<2000000;k++){
synchronized(o){
si++;
}
}
flag.incrementAndGet();
}
代碼三:
[java]
public void run() {
for(int k=0;k<2000000;k++){
synchronized(o){
si++;
o = new Object();
}
}
flag.incrementAndGet();
}
代碼四:
[java]
public void run() {
for(int k=0;k<2000000;k++){
synchronized(o){
si++;
Object temp = o;
o = new Object();
o = temp;
}
}
flag.incrementAndGet();
} 有了這四段代碼我想問題大概可以說明白了,這里說一下輸出吧。
代碼一:<4000000
代碼二:=4000000
代碼三:<4000000
代碼四:<4000000(PS:這個結果非常接近4000000)
這里說明一下我測試中碰到的問題,代碼四一直沒有跑出我想要的結果,主要是開始我設的循環次數太少,其實這里如果要這個現象更加明顯一些可以在中間多new 幾個Object 如下面的代碼五,這樣現象就比較明顯了雅思代考 雅思答案
代碼五:
[java]
public void run() {
for(int k=0;k<2000000;k++){
synchronized(o){
si++;
Object temp = o;
for(int m=0;m<10;m++){
o = new Object();
}
o = temp;
}
}
flag.incrementAndGet();
}
為什么會出現上面的現象:
代碼一:當si做++操作后(可以直接看字節碼,這里不貼了)在putstatic之前有幾步操作,就是我們常說的非原子操作,而這時候si已經不是原來的對象了,這樣鎖對另外一個線程來說就失效了,我想代碼三和代碼四就是最好的佐證,代碼四更有說服力。當時因為沒有出現預想的情況困惑了挺久職稱英語代考 職稱英語答案
其實這里用字節碼來解釋還不是很嚴謹,最好的當然直接是匯編代碼
如有什么問題還希望各位讀者指正。