Java监视器从私有变量返回错误的值

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

我在java中实现了一个屏障,当线程访问它时,它会创建一个新的对象,其中包含一个参数值,存储在一个私有变量中,稍后返回。然后,当另一个线程调用barrier时,它用这个参数完成前一个对象。第一对运行良好,其余的接收与第一对创建的对象相同的对象

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(…)
    更改同步。这里需要小心
  • 我使用
    abarier
    为null或不为null来替换
    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;
    }
}