簡體   English   中英

如何使隨機線程等待,然后在恆定時間后將其喚醒

[英]How to make random thread wait then wake it up after constant time

在主線程中,我創建並啟動四個線程( A,B,C,D ),每500到1000ms在控制台上打印一次字母和數字。 例如A1,A2,A3等。

主線程假設每100毫秒暫停一次隨機Letter線程,然后將其喚醒。 2秒后,它想殺死所有人。

我的問題是我無法暫停隨機Letter線程然后將其喚醒,因為我得到了: IllegalMonitorStateException

我的主線程類:

public class Main extends Thread {
    private boolean alive;
    private ArrayList<Letter> letters;
    private Letter toStop;
    public static Object mutex;

    public Main() {
        letters = new ArrayList<Letter>();
        alive = true;
        mutex = new Object();
    }

        public void run() {
    try {
        Timer timer = new Timer();
        timer.schedule(new StopTask(timer, this), 2 * 1000);
        letters.add(new Letter());
        letters.add(new Letter());
        letters.add(new Letter());
        letters.add(new Letter());
        for (Letter letter : letters) {
            new Thread(letter).start();
        }

        while (alive) {
            synchronized (mutex) {
                toStop = letters.get((int) (Math.random() * letters.size()));
                System.out.println(toStop.getLetter() + " spi");
                mutex.wait();
                Thread.sleep(100);
                mutex.notify();
            }
        for (Letter letter : letters) {
            letter.kill();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

    public void kill() {
        alive = false;
    }

}

和我的Letter課程:

class Letter implements Runnable {
    private static int ID;
    private char letter;
    private int counter;
    private boolean alive;

    public Letter() {
        letter = (char) ('A' + ID);
        alive = true;
        ID++;
    }

    @Override
    public void run() {

        try {
            while (alive) {
                System.out.println(letter + "" + counter);
                counter++;
                Thread.sleep((int) (Math.random() * 501 + 500));
            }
            System.out.println("Watek " + letter + " sie zakonczyl");
        } catch (Exception e) {

        }

    }

    public void kill() {
        alive = false;
    }

    public char getLetter() {
        return letter;
    }

} 

StopTask

import java.util.Timer;
import java.util.TimerTask;

public class StopTask extends TimerTask {
    private Timer timer;
    private Main main;

    public StopTask(Timer timer, Main main) {
        this.timer = timer;
        this.main = main;
    }

    public void run() {
        System.out.println("Time's up!");
        main.kill();
        timer.cancel(); //Not necessary because we call System.exit
    }
}

您的代碼示例不起作用,因為在不擁有對象監視器的情況下進行了wait()調用。

這是javadoc的解釋: https : //docs.oracle.com/javase/7/docs/api/java/lang/Object.html#wait()

這是來自Javadoc的代碼段:

公共最終void wait()引發InterruptedException

使當前線程等待,直到另一個線程為此對象調用notify()方法或notifyAll()方法。 換句話說,此方法的行為就像完全執行調用wait(0)一樣。 當前線程必須擁有該對象的監視器。 線程釋放此監視器的所有權,並等待直到另一個線程通過調用notify方法或notifyAll方法通知等待在此對象監視器上等待的線程喚醒。 然后,線程等待,直到它可以重新獲得監視器的所有權並恢復執行。

與一個參數版本中一樣,可能會產生中斷和虛假喚醒,並且應始終在循環中使用此方法:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait();
     ... // Perform action appropriate to condition
 }

此方法只能由作為該對象的監視器的所有者的線程調用。 有關線程可以成為監視器所有者的方式的描述,請參見notify方法。 拋出:IllegalMonitorStateException-如果當前線程不是對象監視器的所有者。 InterruptedException-如果任何線程在當前線程等待通知之前或之時中斷了當前線程。 引發此異常時,將清除當前線程的中斷狀態。

我將重新設計代碼以使線程自己等待,而不是被告知從外部等待。 例如,使用一些共享對象在線程之間共享狀態。 我還將使用預定的線程執行器。 使生活更輕松: http : //docs.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html

這是一個典型的生產者-消費者問題,並且有更好的解決方法。 由於我們正在解決眼前的問題,因此您可以執行以下操作。

您可以擺脫互斥對象,並使用Letter實例作為互斥對象,這樣有效地就有了4個互斥對象,每個互斥對象與Main

public class Main extends Thread{
    private boolean alive;
    private ArrayList<Letter> letters;
    private Letter toStop;
    //public static Object mutex;

    public Main() {
        letters = new ArrayList<Letter>();
        alive = true;
        mutex = new Object();
    }

    public void run() {
        try {
            Timer timer = new Timer();
            timer.schedule(new StopTask(timer, this), 2 * 1000);
            letters.add(new Letter());
            letters.add(new Letter());
            letters.add(new Letter());
            letters.add(new Letter());

            for (Letter letter : letters) {
                new Thread(letter).start();
            }

            while (alive) {
                // synchronized (mutex) {
                toStop = letters.get((int) (Math.random() * letters.size()));
                synchronized (toStop) {
                    //System.out.println(toStop.getLetter() + " spi");
                    // mutex.wait();
                    //Thread.sleep(100);
                    // mutex.notify();
                    toStop.setToGetLetter(true);
                    toStop.notify();
                }
                System.out.println(toStop.getLetter() + " spi");
                Thread.sleep(100);
            }
            // }
            for (Letter letter : letters) {
                letter.kill();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void kill() {
        alive = false;
    }
}

在您的Letter Thread中,您可以使用this與Main進行協調

public class Letter implements Runnable {
    private static int ID;
    private char letter;
    private int counter;
    private boolean alive;
    private volatile boolean toGetLetter = false;

    public boolean isToGetLetter() {
        return toGetLetter;
    }

    public void setToGetLetter(boolean toGetLetter) {
        this.toGetLetter = toGetLetter;
    }

    public Letter() {
        letter = (char) ('A' + ID);
        alive = true;
        ID++;
    }

    @Override
    public void run() {

        try {
            while (alive) {
                synchronized (this) {
                    while (!isToGetLetter()) {
                        this.wait();
                }
                System.out.println(letter + "" + counter);
                counter++;
                Thread.sleep((int) (Math.random() * 501 + 500));
                toGetLetter = false;
                this.notify();
            }
        }
        System.out.println("Watek " + letter + " sie zakonczyl");
    } catch (Exception e) {

    }
}

    public void kill() {
        alive = false;
    }

    public char getLetter() {
        return letter;
    }
}

暫無
暫無

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

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