如何解决多线程静态变量自增?
How to solve multiple thread static variable incrementation?
所以我的问题本质上是,即使我使用 static 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;
查看这段代码,我们发现我们必须:
- 读取
n
, 的值
- 将其存储在某个临时变量中
result
,
- 增加
1
,
- 将(增加的)值写回
n
所以我们有多个操作。如果这些操作由不同的线程并行执行多次,那么我们可以看到多种可能的交织导致数据不一致。例如,两个线程都可以读取 n
的(当前)值。两者都会将值递增 1,并且都会将新值写回 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();
...
}
}
}
所以我的问题本质上是,即使我使用 static 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;
查看这段代码,我们发现我们必须:
- 读取
n
, 的值
- 将其存储在某个临时变量中
result
, - 增加
1
, - 将(增加的)值写回
n
所以我们有多个操作。如果这些操作由不同的线程并行执行多次,那么我们可以看到多种可能的交织导致数据不一致。例如,两个线程都可以读取 n
的(当前)值。两者都会将值递增 1,并且都会将新值写回 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();
...
}
}
}