[英]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.