簡體   English   中英

調用方法后暫停線程

[英]Pause Thread after a method is called

基本上,我想在調用方法后暫停線程,然后再繼續執行另一個方法。 我無法循環,我的方法只能運行一次。 其背后的想法是在游戲中使用,該方法將顯示消息,並且每當用戶按下一個鍵時,就會顯示下一條消息。 我不能只瀏覽列表,因為游戲需要用戶輸入。 我看了看Thread.pause()Thread.resume()但它們都不起作用,並且已被棄用。 我目前的程式碼(無法運作):

private Thread thread;
private Thread managerThread;
private final Object lock = new Object();

private boolean shouldThreadRun = true;
private boolean storyRunning = true;

public Storyline() {
    setUpThread();
}

private void setUpThread() {
    managerThread = new Thread(() -> {
        while(storyRunning) {
            synchronized (lock) {
                if(!shouldThreadRun) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("Looping");
            }
        }
    });
    thread = new Thread(() -> {
        synchronized (lock) {
            pauseThread();
            System.out.print("A");
            pauseThread();
            System.out.print("B");
        }
    });
    managerThread.start();
    thread.start();
}

public void pauseThread() {
    shouldThreadRun = false;
}
public void resumeThread() {
    shouldThreadRun = true;
}

查看我的修改,看看它是否與您要實現的內容相似。 我正在使用掃描儀來模擬用戶輸入,只需按鍵盤上的Enter即可嘗試。 順便說一句,我希望這只是一種鍛煉,而不是現實生活中的情況。 除非確實有必要,否則您應嘗試避免在實際產品中進行這種低級別的多線程管理,在這種情況下,您仍應使用為此目的使用的適當數據結構。 在實際的應用程序中,按鈕將鏈接到回調,並且您將設置一些onClick()方法以在按下按鈕后立即執行所需的代碼。

關於並發,我強烈建議您看一下這些教程: Oracle-Concurrency

PS:請注意,我完全忽略了中斷,這是一種不好的做法,應該以正確的方式處理這些異常:我只是試圖通過使代碼盡可能簡單來實現所需的結果。 另外,就像其他人指出的那樣,您應該通過在循環內調用wait來處理虛假喚醒。

private Thread thread;
private Thread managerThread;
private final Object lock = new Object();

Scanner in;

public Storyline() {
    setUpThread();
}

private void setUpThread() {
    managerThread = new Thread(() -> {
        while(true) {
            in = new Scanner(System.in);
            in.nextLine();
            resumeThread(); 
        }
    });
    thread = new Thread(() -> {
        synchronized (lock) {
            while(true){
                System.out.print("A");
                try {
                    lock.wait();
                } catch (InterruptedException e) {}
                System.out.print("B");
                try {
                    lock.wait();
                } catch (InterruptedException e) {}
            }
        }
    });
    managerThread.start();
    thread.start();
}


public void resumeThread() {
    synchronized(lock){
        lock.notify();
    }
}

文檔中所述 ,Object.wait的第一條規則是必須在循環中調用該規則,該循環取決於等待的基礎條件。

因此,您的等待需要看起來像這樣:

synchronized (lock) {
    while (!shouldThreadRun) {
        lock.wait();
    }
}

中斷不是偶然發生的事情。 僅當另一個線程明確要求它停止正在執行的操作並干凈地退出時,該線程才會被中斷。

因此,如果收到中斷,則正確的做法是不要忽略該中斷並打印堆棧跟蹤。 您需要干凈地退出。

最簡單的方法是將整個while循環包含在try / catch中:

try {
    while (storyRunning) {
        synchronized (lock) {
            while (!shouldThreadRun) {
                lock.wait();
            }
            System.out.println("Looping");
        }
    }
} catch (InterruptedException e) {
    System.out.println("Exiting, because someone asked me to stop.");
    e.printStackTrace();
}

這樣,您的while循環將在被中斷時自動退出。

最后,除非另一個線程在與等待線程同步的同一對象上調用Object.notify或Object.notifyAll,否則Object.wait是無用的。 除非對象得到通知,否則wait方法可能不會返回:

public void pauseThread() {
    synchronized (lock) {
        shouldThreadRun = false;
        // Tell waiting thread that shouldThreadRun may have changed.
        lock.notify();
    }
}

public void resumeThread() {
    synchronized (lock) {
        shouldThreadRun = true;
        // Tell waiting thread that shouldThreadRun may have changed.
        lock.notify();
    }
}

請注意,同步在方法內部。 如果您一直保持線程同步在lock狀態,則管理器線程將永遠不會有運行的機會,因為它試圖獲取同一對象的同步鎖定。 (但是,相反的情況並非如此;管理器線程可以一直保持lock同步,因為wait()方法將暫時釋放同步鎖,從而允許另一個線程繼續執行。)

如果所有訪問shouldThreadRun代碼都在同步塊內部,則無需(也不應)使shouldThreadRun易變,因為同步已經確保了多線程的一致性。

暫無
暫無

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

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