Java监视器从私有变量返回错误的值
我在java中实现了一个屏障,当线程访问它时,它会创建一个新的对象,其中包含一个参数值,存储在一个私有变量中,稍后返回。然后,当另一个线程调用barrier时,它用这个参数完成前一个对象。第一对运行良好,其余的接收与第一对创建的对象相同的对象Java监视器从私有变量返回错误的值,java,multithreading,concurrency,synchronized,monitor,Java,Multithreading,Concurrency,Synchronized,Monitor,我在java中实现了一个屏障,当线程访问它时,它会创建一个新的对象,其中包含一个参数值,存储在一个私有变量中,稍后返回。然后,当另一个线程调用barrier时,它用这个参数完成前一个对象。第一对运行良好,其余的接收与第一对创建的对象相同的对象 private Barrier aBarrier; private boolean first = true; public synchronized Barrier pairUp(int id){ try{ if(fi
private Barrier aBarrier;
private boolean first = true;
public synchronized Barrier pairUp(int id){
try{
if(first){
first = false;
aBarrier = new Barrier(); aBarrier.setFirst(id);
wait();
}
else{
first = true;
aBarrier.setLast(id);
notify();
}
}
catch(InterruptedException e){System.out.printf("ERROR");}
return aBarrier;
}
这就是调用上述方法的每个进程的样子
private int id = ID OF THE PROCESS, 14 RUN CONCURRENTLY SO FROM 0 TO 13 (this is set in the constructor method);
public void run() {
while(true){
myBarrier = pairUp(id);
myBarrier.goThrough();
//Do stuff that doesn't matter here
// ....
}
}
一个Barrier对象包含两个整数和一个稍后执行更多操作的方法。
如果我在调用之前或之后将私有变量abarier重置为null,它总是返回null。
我觉得我错过了一些愚蠢的事情
如果流程在第一对之后调用方法pairUp(),它将获得第一个屏障。
我用这个来区分在pairUp方法中哪个过程首先出现
事先谢谢
一个Barrier对象包含两个整数和一个稍后执行更多操作的方法。如果我在调用之前或之后将私有变量abarier重置为null,它总是返回null。我觉得我错过了一些愚蠢的事情
我认为问题在于,您在等待/通知调用之后返回了abarier
,但它可能已被后续线程更改。将其存储在局部变量中以使其不被更改是关键
您可能还拥有包装对象的多个版本,因此您的synchronized
语句正在另一个对象上同步
下面代码中需要注意的几点:
更改同步。这里需要小心System.out.println(…)
- 我使用
为null或不为null来替换abarier
布尔值first
public类Foo实现Runnable{
私有静态int NUM_线程=14;
私有静态最终AtomicInteger idCounter=新的AtomicInteger();
私有静态最终执行器服务线程池=Executors.newFixedThreadPool(NUM_线程);
专用静态屏障ABARIER=null;
公共静态void main(字符串[]args){
//只有一个Foo对象
Foo-Foo=新的Foo();
对于(inti=0;i
发布一个完整的程序,再现错误。告诉我们您希望程序做什么,以及它做什么。我看不到在哪里声明了abarier和first。我怀疑你的问题在于这些变量。我们需要了解整件事,它与波动性无关。这是因为比赛条件。请告诉我们你看到了什么是错误的-我想你以前有过,但你似乎已经删除了它。
public class Foo implements Runnable {
private static int NUM_THREADS = 14;
private static final AtomicInteger idCounter = new AtomicInteger();
private static final ExecutorService threadPool = Executors.newFixedThreadPool(NUM_THREADS);
private static Barrier aBarrier = null;
public static void main(String[] args) {
// only 1 Foo object
Foo foo = new Foo();
for (int i = 0; i < NUM_THREADS; i++) {
threadPool.execute(foo);
}
}
public synchronized Barrier pairUp(int id) {
Barrier barrier = aBarrier;
try {
if (barrier == null) {
barrier = new Barrier();
barrier.first = id;
aBarrier = barrier;
wait();
} else {
barrier.last = id;
aBarrier = null;
notify();
}
} catch (InterruptedException e) {
// always a good pattern
Thread.currentThread().interrupt();
e.printStackTrace();
barrier = null;
}
// return local barrier because aBarrier might have changed
return barrier;
}
@Override
public void run() {
int id = idCounter.incrementAndGet();
while (true) {
Barrier myBarrier = pairUp(id);
// System.out.println is synchronized so it may move the bug
System.out.println(id + ": " + myBarrier.first + " and " + myBarrier.last);
}
}
private static class Barrier {
int first;
int last;
}
}