我是 Java 編程的新手,也是第一次嘗試執行緒。我創建了一個執行緒來列印偶數,然后創建一個執行緒來列印奇數。在奇數執行緒中,要列印的數字 11 后面有一個 suspend() 方法。之后還有另一個塊來列印從 13 到 21 的奇數。在 main() 中,我加入了 2 個執行緒。在主函式中,我首先呼叫執行緒 t1(偶數),然后將它與執行緒 t2(奇數)連接起來。由于有暫停,它將在列印 11 后暫停輸出。但是在那之后,當我呼叫 t2.resume() 時,它不會繼續列印 13 到 21。為什么它不列印其余的?我怎樣才能讓它恢復?
這是代碼,請看:
class Hi extends Thread {
public void run(){
try{
for(int i=0; i<=10; i ){
System.out.println("1st: " (2*i));
sleep(100);
}
} catch(Exception e){
System.out.println(e);
}
}
}
class Hello extends Thread {
public void run(){
try {
for(int i=0; i<=5; i ){
System.out.println("2nd: " (2*i 1));
}
suspend();
System.out.println(" Resumes again");
for(int i=6; i<=10; i ){
System.out.println("2nd: " (2*i 1));
}
} catch(Exception e){
System.out.println(e);
}
}
}
public class thread {
public static void main(String args[]){
Hi t1 = new Hi();
Hello t2 = new Hello();
t1.start();
try {
t1.join();
} catch (Exception e) {
}
t2.start();
t2.resume();
}
}
輸出:
1st: 0
1st: 2
1st: 4
1st: 6
1st: 8
1st: 10
1st: 12
1st: 14
1st: 16
1st: 18
1st: 20
Exception in thread "main" 2nd: 1
java.lang.IllegalThreadStateException
2nd: 3
2nd: 5
2nd: 7
2nd: 9
2nd: 11
at java.base/java.lang.Thread.start(Thread.java:791)
at thread.main(thread.java:57)
在此之后程式沒有退出,我必須在終端中手動退出程式(ctrl c)。
uj5u.com熱心網友回復:
在此之后程式沒有退出,我必須在終端中手動退出程式(ctrl c)。
除了您不應該使用suspend()and 之外resume(),我相信您的問題是典型的競爭條件。主執行緒正在呼叫t2.start()然后t2.resume()但執行緒尚未掛起。主執行緒拋出例外,然后t2執行緒完成列印并呼叫suspend(). 沒有人可以恢復它,所以執行緒永遠不會結束,你必須控制-c 你的程式。
您應該對示例代碼進行一些更改。首先使用等待/通知而不是suspend(). 例如,讓Hello執行緒執行以下操作:
// t2 thread shouldn't use suspend which is deprecated for good reason
synchronized (this) {
wait();
}
然后在主執行緒中,您需要回圈直到執行緒處于等待狀態,然后再通知它。就像是:
while (true) {
if (t2.getState() == State.WAITING) {
synchronized (t2) {
t2.notify();
}
break;
}
Thread.sleep(100);
}
這些型別的執行緒練習,其中一個執行緒與另一個執行緒被鎖定(除了join()末尾的 a)是執行緒 IMO 的一個不好的例子。
其他一些評論。您應該在代碼末尾join()使用Hello執行緒,Exception如果可以幫助它,則永遠不要捕獲它,因為它隱藏了可能是問題根源的例外(至少按照@GhostCat 推薦的方式列印它們),并且在以下情況下始終重新中斷您的執行緒你抓住InterruptedException:
try {
t2.join();
} catch (InterruptedException e) {
// always a good pattern
Thread.currentThread().interrupt();
e.printStackTrace();
}
uj5u.com熱心網友回復:
當我打電話時
t2.resume(),它不會繼續列印 13 到 21。為什么它不列印其余的?
@Gray 回答了那個。TLDR:您的主執行緒t2.resume() 在您的t2執行緒呼叫之前呼叫suspend()。
我很想知道您使用的是什么 Java 版本。我在 macOS 上運行 JDK11,我無法讓你的程式拋出那個java.lang.IllegalThreadStateException,但我猜在你使用的任何 JDK 和作業系統中,當你的主執行緒嘗試resume()一個不是的執行緒時會拋出例外t 暫停。
我怎樣才能讓它恢復?
我會使用一個Semaphore.
讓t2執行緒等待,以acquire()從信號量“許可證”,并讓主執行緒release()許可證到的信號在適當的時間。
我更改了您的程式,將suspend()呼叫替換為sem.acquire(),并將resume()呼叫替換為sem.release()。我還在Thread.sleep()主執行緒釋放信號量之前呼叫了它,以便您可以看到暫停。這是整件事:
import java.util.concurrent.Semaphore;
class Hi extends Thread { // This class is exactly the same as yours.
public void run(){
try{
for(int i=0; i<=10; i ){
System.out.println("1st: " (2*i));
sleep(100);
}
} catch(Exception e){
System.out.println(e);
}
}
}
class Hello extends Thread {
private Semaphore sem; // new member variable
public Hello(Semaphore sem) { // new constructor to set the new member.
this.sem = sem;
}
public void run(){
try {
for(int i=0; i<=5; i ){
System.out.println("2nd: " (2*i 1));
}
// Wait to "acquire" a permit from the semaphore. This won't
// return until the main thread "releases" a permit _to_ the
// semaphore.
sem.acquire();
System.out.println(" Resumes again");
for(int i=6; i<=10; i ){
System.out.println("2nd: " (2*i 1));
}
} catch(Exception e){
System.out.println(e);
}
}
}
public class Wonk {
public static void main(String args[]){
// Create a semaphore that initially has 0 "permits."
Semaphore s = new Semaphore(0);
Hi t1 = new Hi();
Hello t2 = new Hello(s);
t1.start();
try {
t1.join();
} catch (Exception e) {
}
t2.start();
waitabit(5000); // Sleep 5 seconds, and then...
s.release(); // ...Release the Hounds!!
}
private static void waitabit(int numMilliseconds) {
try {
Thread.sleep(numMilliseconds);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/359319.html
