本文介紹了如何解決多線程靜態變量遞增?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!
問題描述
所以我的問題本質上是,即使我使用靜態的可變int變量進行遞增,我的一些數據也不是唯一的,這將是我的目標(我為我的元素編號)。
public class Producer implements Runnable{
private String str;
private Fifo f;
private int i;
private static volatile int n=0;
public Producer(String str,int i,Fifo f) ....
public void run() {
try {
this.go();
} catch (InterruptedException e) {
;
}
}
void go() throws InterruptedException {
while(true) {
Thread.sleep(i);
int l=n++;
String k=str+" "+l+" ";
f.put(k);
System.out.println("produced "+str+" "+l+" "+System.currentTimeMillis()%100000);
}
}
}
我的問題出在go()函數中。我給我的元素編號,我有多個生產者對象作為獨立的線程運行,但有時它們表現得好像不知道n是否已經更新,所以我得到了相同的索引。
有什么主意嗎?
(我知道可能是什么問題,但我不知道如何解決它。)
推薦答案
似乎對volatile
的作用存在誤解。關鍵字volatile
引入了寫入和讀取之間的先發制人語義。但是,它不會使多個操作成為原子操作。
如果我們手寫n++
";的語義(請不要這樣做,它僅用于解釋目的),它將如下所示:
final int result;
n = (result = n) + 1;
Ideone demo
查看此代碼,我們看到我們必須:
-
讀取
n
,的值將其存儲在某個臨時變量中
result
,遞增
1
,將(遞增的)值寫回
n
所以我們有多個操作。如果這些操作由不同的線程多次并行執行,那么我們可以看到導致數據不一致的多種可能的交織。例如,兩個線程都可以讀取n
的(當前)值。兩者都會將值加一,并且都會將新值寫回n
。這意味著有兩個線程執行了";增量";,但n
的值只增加了1
,而不是2
。
我們可以使用專門的類–在本例中是AtomicInteger
–來避免這個問題。用法如下所示:
public class Producer implements Runnable {
...
private static final AtomicInteger n = new AtomicInteger(0);
...
void go() throws InterruptedException {
while(true) {
...
int l = n.getAndIncrement();
...
}
}
}
這篇關于如何解決多線程靜態變量遞增?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,