我正在嘗試使用 2 個執行緒列印出 arraylist 的內容,我的主要目標是讓執行緒以同步的方式讀取 arraylist 并列印其內容。即使我使用同步塊,我仍然收到 IllegalMonitorStateException。我知道這是一個基本問題,但我無法讓它作業,請原諒我。
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Q1 {
public static Q1 yeni;
public static void main(String[] args) {
// TODO Auto-generated method stub
yeni = new Q1();
}
Q1() {
List<String> list = Collections.synchronizedList(new ArrayList<String>());
list.add("a1");
list.add("b1");
list.add("c1");
list.add("d1");
list.add("e1");
list.add("f1");
ExecutorService executorService = Executors.newFixedThreadPool(10);
synchronized (list) {
myThread thread1 = new myThread(list);
myThread thread2 = new myThread(list);
thread1.start();
thread2.start();
}
}
}
這是 myThread 類
import java.util.*;
public class myThread extends Thread {
List<String> liste;
public myThread(List<String> liste) {
this.liste = liste;
}
@Override
public void run() {
try {
synchronized (Q1.yeni) {
System.out.println("Thread number " this.getName() " started running.");
for (int i = 0; i < liste.size(); i ) {
System.out.println(liste.get(i));
this.wait(3000);
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
uj5u.com熱心網友回復:
的原因IllegalMonitorStateException是您在呼叫wait物件 ( this) 時沒有持有該物件的監視器。您必須使用synchronized (this)塊包裝此呼叫,或呼叫此代碼已同步wait的 on 。Q1.yeni
但是,看起來使用wait可能是錯誤的。此方法用于等待某個條件,該條件通過對同一物件的呼叫notify或notifyAll在同一物件上發出信號。由于此代碼中沒有明顯的條件,也沒有使用notifyor notifyAll,我懷疑您真正想要呼叫的是this.sleep(3000),它將執行緒暫停三秒鐘,然后在該持續時間過去后恢復它。
該sleep方法不需要任何監視器的所有權,并且不釋放持有的監視器的所有權,因此synchronized (Q1.yeni)當一個執行緒當前處于睡眠狀態時,另一個執行緒將無法進入該塊。這意味著進入該塊的第一個執行緒將運行完成,遍歷整個串列,然后第二個執行緒有機會開始。目前尚不完全清楚這是否是這里的意圖。
有關更多使用資訊,Object.wait請參閱檔案。Thread.sleep
第二個問題是Q1.yeni這些執行緒必須在初始化之前訪問,因為執行緒是在Q1建構式中啟動的,并且陳述句只在建構式完成后進行yeni = new Q1();賦值。yeni在這種情況下,使用執行緒可能會更好synchronized (liste)。
除此之外,synchronized (list)在Q1建構式中的作用不大,因為主執行緒不會訪問或操作該list部分中的內容。唯一實際的影響是它啟動的執行緒在到達第一次呼叫時會阻塞,liste.size()直到主執行緒退出synchronized (list)(在啟動兩個執行緒后立即)。這可能會稍微減慢運行的第一個執行緒,但不會影響程式的執行緒安全或正確性。
我還建議查看“如何在 Java 中處理 InterruptedException”。在這種情況下,我建議在例外處理程式中恢復中斷狀態。
總而言之,這是此代碼的修改示例(包括其他小的更改,以洗掉未使用的代碼和樣板注釋、改進格式并確保與 Java 命名約定的一致性):
Q1.java:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Q1 {
private static Q1 yeni;
public static void main(String[] args) {
yeni = new Q1();
}
Q1() {
List<String> list = Collections.synchronizedList(new ArrayList<>());
list.add("a1");
list.add("b1");
list.add("c1");
list.add("d1");
list.add("e1");
list.add("f1");
MyThread thread1 = new MyThread(list);
MyThread thread2 = new MyThread(list);
thread1.start();
thread2.start();
}
}
MyThread.java:
import java.util.*;
public class MyThread extends Thread {
private final List<String> liste;
public MyThread(List<String> liste) {
this.liste = liste;
}
@Override
public void run() {
try {
synchronized (liste) {
System.out.println("Thread number " this.getName() " started running.");
for (int i = 0; i < liste.size(); i ) {
System.out.println(liste.get(i));
sleep(3000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
interrupt();
}
}
}
輸出:
Thread number Thread-0 started running.
a1
b1
c1
d1
e1
f1
Thread number Thread-1 started running.
a1
b1
c1
d1
e1
f1
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/417319.html
標籤:
上一篇:如何并行寫入容器
