我有多个线程来粗略地计算给定数组的总和。我不能使用单独的工作线程和控制器,而是整个程序必须写在一个类中。程序的要点是打印计算结果,使得线程id 0是第一个打印结果,然后是线程id 1,然后是线程id 2,依此类推。
我在类中编写了两个同步方法:finished
- 一旦特定线程完成计算就通知所有线程,waitForThread
- 等待ID小于其自身的线程仍然没有&{ #39; t完成了。
因为我不能使用单独的控制器类,所以我决定创建一个静态数组doneArr
,其中每个单元格表示一个线程id,一旦线程完成其工作,它就会更新{ {1}}。这种方式doneArr
知道何时等待。
我似乎无法让这个工作,请你指出正确的方向吗?
编辑:使用waitForThread
可以轻松解决问题,但我正在寻找使用同步的解决方案。
这是代码:
join()
答案 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的方法。这对于共享对象上的方法非常有用,但实际上并不是你拥有的 - 你有多个唯一的工作对象。因此,您实际上并未在同一对象上进行同步。这意味着:
notifyAll()
的电话实际上并没有完成任何事情。相反,请使用声明为static final
的锁定对象。
private static final Object lockObj = new Object();
private void waitForThread() {
synchronized(lockObj) {...}
}
private void finished() {
synchronized(lockObj) {...}
}
process(...)
方法是一个实例方法,但它作为参数引用它已有权访问的实例变量。final
。