如何在一个类中同步多线程应用程序,没有工作线程和控制器?

时间:2018-02-18 07:49:17

标签: java multithreading

我有多个线程来粗略地计算给定数组的总和。我不能使用单独的工作线程和控制器,而是整个程序必须写在一个类中。程序的要点是打印计算结果,使得线程id 0是第一个打印结果,然后是线程id 1,然后是线程id 2,依此类推。

我在类中编写了两个同步方法:finished - 一旦特定线程完成计算就通知所有线程,waitForThread - 等待ID小于其自身的线程仍然没有&{ #39; t完成了。

因为我不能使用单独的控制器类,所以我决定创建一个静态数组doneArr,其中每个单元格表示一个线程id,一旦线程完成其工作,它就会更新{ {1}}。这种方式doneArr知道何时等待。

我似乎无法让这个工作,请你指出正确的方向吗?

编辑:使用waitForThread可以轻松解决问题,但我正在寻找使用同步的解决方案。

这是代码:

join()

1 个答案:

答案 0 :(得分:1)

你反复初始化同一个静态成员,虽然这里是无害的,但这是一个相当糟糕的做法。相反,使用静态初始化块来初始化静态变量(而不是构造函数)。

private static final int[] doneArr;
static {
    for(...) {...}
}

但是,当然,在这种情况下,你遇到的问题是它的长度是可变的。我还注意到doneArr包含整数,但您只是将它用作标志(即-1或!-1)。相反,请使用Map<Integer, Boolean>

private static final Map<Integer, Boolean> threadIsDone = new HashMap<>();

public WorkThread(int[] vec, int id) {
    threadIsDone.put(id, false);
    ...
}

一旦你这样做了,虽然在这个特殊情况下并不是绝对必要的,但在你检查它时,仍然是一个好的做法来防止缺失值。

private boolean finishedUpToMe() {
    for(int i = 0; i < id; i++) {
        final Boolean threadDone = threadIsDone.get(i);
        if (threadDone != null && !threadDone)
            return false;
    }
    return true;
}

至于您的线程问题,您似乎使用了声明为synchronized的方法。这对于共享对象上的方法非常有用,但实际上并不是你拥有的 - 你有多个唯一的工作对象。因此,您实际上并未在同一对象上进行同步。这意味着:

  • JVM不必使写入对其他线程可见。
  • 如果写入确实可见,则表示您处于竞争状态。
  • notifyAll()的电话实际上并没有完成任何事情。

相反,请使用声明为static final的锁定对象。

private static final Object lockObj = new Object();

private void waitForThread() {
    synchronized(lockObj) {...}
}

private void finished() {
    synchronized(lockObj) {...}
}

编辑:其他想法

  • 如果您声明的变量更接近实际使用位置(即紧接在相应方法之上),您的代码将更具可读性。
  • 您的process(...)方法是一个实例方法,但它作为参数引用它已有权访问的实例变量。
  • 如果您不打算修改variety of reasons,则应声明变量final