【问题标题】:Java monitor returns wrong value from private variableJava 监视器从私有变量返回错误值
【发布时间】:2014-11-24 11:42:20
【问题描述】:

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

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 对象包含两个整数和一个稍后做更多事情的方法。 如果我在调用之前或之后将私有变量 aBarrier 重置为 null,它总是返回 null。 我觉得我在这里错过了一些愚蠢的事情。

如果一个进程在第一对之后调用方法pairUp(),它将获得第一个屏障。 我用它来区分pairUp方法中哪个进程先出现。

先谢谢了!

【问题讨论】:

  • 发布一个完整的程序来重现错误。告诉我们您希望该程序做什么,以及它会做什么。
  • 我看不到任何地方声明了 aBarrier 和 first 。我怀疑你的问题在于这些变量。我们需要看到整个事情。
  • 它与 volatile 无关。这是因为比赛条件。
  • 请告诉我们你看到了什么错误 - 我想你以前有过它,但你似乎已经删除了它。

标签: java multithreading concurrency synchronized monitor


【解决方案1】:

一个 Barrier 对象包含两个整数和一个稍后做更多事情的方法。如果我在调用之前或之后将私有变量 aBarrier 重置为 null,它总是返回 null。我觉得我在这里错过了一些愚蠢的事情。

我认为问题在于您在等待/通知调用之后返回aBarrier,但它可能已被后续线程更改。将其存储在局部变量中以使其不会被更改是关键。

您可能还拥有多个版本的包装对象,因此您的 synchronized 语句在不同的对象上同步?

在下面的代码中要注意几点:

  • System.out.println(...) 更改同步。这里需要小心。
  • 我使用 aBarrier 是否为空来替换 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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-06
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多