如何解决多线程静态变量增量?



所以我的问题本质上是,即使我使用静态volatile 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()。我给元素编号,我有多个Producer对象作为独立线程运行,但有时它们表现得好像不知道n是否被更新了,所以我得到了相同的索引。什么好主意吗?(我知道可能是什么问题,但我不知道如何解决它。)

对于volatile的作用似乎存在误解。关键字volatile在写和读之间引入了happens-before语义。但是,它不能使多个操作原子化。

如果我们要"手写"n++的语义;(请不要这样做,这只是为了说明目的),它看起来像这样:

final int result;
n = (result = n) + 1;
<<p>

Ideone演示/kbd>看一下这段代码,我们看到我们必须:

  1. 读取n值,
  2. 将其存储在某个临时变量result中,
  3. 增加1
  4. 将(递增的)值写回n

所以我们有多个操作。如果这些操作由不同的线程并行执行多次,那么我们可以看到大量可能导致数据不一致的交织。例如,两个线程都可以读取n的(当前)值。两者都将值增加1,并将新值写回n。这意味着两个线程执行了"increment",但是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();
...
}
}
}

相关内容

  • 没有找到相关文章

最新更新