在使用 2个线程的相同方法时遇到麻烦。
问题是:看起来当一个线程调用method且方法正在运行,而同时另一个线程尝试调用同一方法时,Java只是跳过该调用!因此,当2个线程调用同一方法时,该方法仅被调用一次。因此,有时随机编程只是跳过方法而根本不执行代码!怎么可能?在不同的机器上尝试过,它的工作方式绝对不符合预期,对我来说,这看起来像是一个可怕的Java错误。
如果有任何专家会读这篇文章,请您描述一下发生的事情,如果是已知问题,请给我链接以进行解释。谢谢!
PS:该代码可以正常运行,您甚至可以将其粘贴到repl.it之类的在线Java中。 在 a.updateCounter(inc); 之后,我检查增量器是否起作用(第45行)。
class Main {
public static void main(String[] args) {
ThreadOne t1 = new ThreadOne(1000, 300, "Thread 1");
ThreadOne t2 = new ThreadOne(1, 300, "Thread 2");
Thread one = new Thread(t1);
Thread two = new Thread(t2);
one.start();
two.start();
}
}
class Accum {
private static Accum a = new Accum();
private int counter = 0;
private Accum() {}
public static Accum getAccum() {
return a;
}
public void updateCounter(int add) {
counter += add;
}
public int getCount() {
return counter;
}
}
class ThreadOne implements Runnable {
Accum a = Accum.getAccum();
int inc;
int max;
String threadName;
ThreadOne(int i, int c, String name) {
inc = i;
max = c;
threadName = name;
}
public void run() {
for(int x = 0; x < max; x++) {
int check = a.getCount();
a.updateCounter(inc);
if(check + inc != a.getCount()) System.out.println("\nupdateCounter was skipped at x " + x + "\nThread name: " + threadName);
try {
Thread.sleep(5);
} catch(InterruptedException ex) {
System.out.println("x: " + x + "\n ex: " + ex);
}
}
System.out.println(threadName + ": " + a.getCount());
}
}
答案 0 :(得分:5)
首先,Java不会跳过该调用。只是实际结果与您的测试不符。
在int check = a.getCount();
和测试if(check + inc != a.getCount())
之间,计数器只是通过另一个线程更改了。就这么简单。
更新:
操作counter += add
不是ATOMIC,也就是说,您可以将其视为3个操作的序列:
counter
的值counter
现在,假设有2个线程恰好在同一时间执行此序列,并且您了解了为什么该值不会增加。
解决方案使此调用成为原子调用:只需使用@gudok提到的AtomicInteger
:
import java.util.concurrent.atomic.AtomicInteger;
public class Accum {
private static Accum a = new Accum();
private AtomicInteger counter = new AtomicInteger(0);
private Accum() {}
public static Accum getAccum() {
return a;
}
public void updateCounter(int add) {
counter.addAndGet(add);
}
public int getCount() {
return counter.intValue();
}
}