[英]How to synchronize multithreaded app in one class, without worker threads and controller?
我有多个线程可以大致计算给定数组的总和。 我不能使用单独的工作线程和控制器,而是必须将整个程序编写在一个类中。 程序的重点是打印计算结果,以便线程ID 0是第一个打印结果的线程,然后是线程ID 1,然后是线程ID 2,依此类推。
我在该类中编写了两个同步方法: finished
-在特定线程完成计算finished
通知所有线程,而waitForThread
等待ID小于其自身线程的线程还没有完成。
因为不能使用单独的控制器类,所以我决定创建一个静态数组doneArr
,其中每个单元格都代表一个线程ID,并且一旦线程完成其工作,它将更新doneArr
的相应单元格。 这样, waitForThread
知道何时等待。
我似乎无法正常工作,能否请您指出正确的方向?
编辑:可以通过使用join()
轻松解决问题,但是我正在寻找使用同步的解决方案。
这是代码:
public class WorkThread extends Thread {
private int[] vec;
private int id;
private int result;
private static int[] doneArr;
private static int progress = 0;
public WorkThread(int[] vec, int id) {
this.vec = vec;
this.id = id;
doneArr = new int[vec.length];
for(int i = 0; i < doneArr.length; i++) {
doneArr[i] = -1; //default value
}
}
private boolean finishedUpToMe() {
for(int i = 0; i < id; i++) {
if(doneArr[i] == -1)
return false;
}
return true;
}
private synchronized void waitForThread() throws InterruptedException {
while(!finishedUpToMe() && id > 0)
this.wait();
progress++;
}
private synchronized void finished() throws IllegalMonitorStateException {
this.notifyAll();
}
public int process(int[] vec, int id) {
int result = 0;
System.out.format("id = %d\n", this.id);
for(int i = 0; i < vec.length; i++) {
vec[i] = vec[i] + 1;
result = result + vec[i];
}
return result;
}
public void run() {
try {
this.waitForThread();
}catch (InterruptedException e) {
System.out.println("waitForThread exception");
}
result = process(vec, id);
doneArr[id] = id;
System.out.format("id = %d, result = %d\n", id, result);
try{
this.finished();
}catch (IllegalMonitorStateException e) {
System.out.format("finished exception\n");
}
}
public static void main(String[] args) {
int[] vec = {1,2,3,4};
WorkThread[] workers = new WorkThread[3];
for(int i = 0; i < workers.length; i++) {
workers[i] = new WorkThread(vec, i);
}
for(int i = 0; i < workers.length; i++) {
workers[i].start();
}
System.out.format("main\n");
}
}
您反复初始化相同的静态成员,尽管这样做无害,但这是一个相当糟糕的做法。 而是使用静态初始化块来初始化静态变量(而不是构造函数)。
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;
}
至于您的线程问题,似乎您使用了声明为已同步的方法。 这对于共享对象上的方法非常有用,但是实际上并不是您所拥有的-您有多个唯一的工作程序对象。 因此,您实际上并没有在同一个对象上进行同步。 这意味着:
notifyAll()
的调用实际上并没有完成任何事情。 而是使用声明为static final
的锁对象。
private static final Object lockObj = new Object();
private void waitForThread() {
synchronized(lockObj) {...}
}
private void finished() {
synchronized(lockObj) {...}
}
process(...)
方法是一个实例方法,但是将对它已经可以访问的实例变量的引用作为参数。 final
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.