簡體   English   中英

使用線程打印 arraylist 時出現 IllegalMonitorStateException

[英]Getting IllegalMonitorStateException while printing arraylist using threads

我正在嘗試使用 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 class

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();
    }

    }

    }

IllegalMonitorStateException的原因是您在 object ( this ) 上調用wait而不持有該 object 的監視器。 您必須使用synchronized (this)塊包裝此調用,或在此代碼已同步的Q1.yeni上調用wait

但是,看起來使用wait可能是錯誤的。 此方法用於等待某個條件,該條件通過調用同一 object 上的notifynotifyAll來發出信號。 由於此代碼中沒有明顯的條件,並且沒有使用notifynotifyAll ,我懷疑您真正想要調用的是this.sleep(3000) ,它將線程暫停三秒鍾,然后在該持續時間過去后恢復它.

sleep方法不需要任何監視器的所有權,也不會釋放持有的監視器的所有權,因此另一個線程將無法在當前睡眠時進入synchronized (Q1.yeni)塊。 這意味着進入該塊的第一個線程將運行完成,遍歷整個列表,然后第二個線程有機會開始。 目前尚不完全清楚這是否是這里的意圖。

有關更多使用信息,請參閱Object.waitThread.sleep的文檔。

第二個問題是, Q1.yeni在它必須初始化之前就被這些線程訪問了,因為線程是在Q1構造函數中啟動的,並且語句yeni = new Q1(); 僅在構造函數完成后分配yeni 在這種情況下,線程使用synchronized (liste)可能會更好。

除此之外,在Q1構造函數中使用synchronized (list)並沒有太大的作用,因為主線程不會訪問或操作該部分中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();
        }
    }
}

Output:

Thread number Thread-0 started running.
a1
b1
c1
d1
e1
f1
Thread number Thread-1 started running.
a1
b1
c1
d1
e1
f1

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM