今天要學的是 Deadlock
Deadlocks.java
import java.util.Random;public class Deadlocks {
public static void main(String[] args) {
Message message = new Message();
(new Thread(new Writer(message))).start();
(new Thread(new Reader(message))).start(); }
}class Message {
private String message;
private boolean empty = true; public synchronized String read() {
while (empty) { }
empty = true;
return message;
} public synchronized void write(String message) {
while (!empty) { }
empty = false;
this.message = message; }
}class Writer implements Runnable {
private Message message; public Writer(Message message) {
this.message = message;
} public void run() {
String messages[] = {
"Humpty Dumpty sat on a wall",
"Humpty Dumpty had a great fall",
"All the king's horse and all the king's men",
"Couldn't put Humpty together again."
}; Random random = new Random(); for (int i = 0; i < messages.length; i++) {
message.write(messages[i]);
try {
Thread.sleep(random.nextInt(2000));
} catch (InterruptedException e) { }
}
message.write("Finished"); }
}class Reader implements Runnable {
private Message message; public Reader(Message message) {
this.message = message;
} public void run() {
Random ramdom = new Random();
for (String latestMessage = message.read(); !latestMessage.equals("Finished");
latestMessage = message.read()) {
System.out.println(latestMessage);
try {
Thread.sleep(random.nextInt(2000));
} catch (InterruptedException e) { }
} }
}
輸出結果:
Humpty Dumpty sat on a wall
這裡做了兩個 Thread,有 implements Runnable
的兩個就是,一個是讀取,一個是寫入
可以看到在 Message
裡面的兩個 Method
都有使用 synchronized
而輸出結果只顯示了一句,照理說要四句都顯示出來
這裡的條件是要等待 empty
的 bool
改變才能跳出 while
但因為使用了 synchronized
造成第一個 Thread 進去後,其他 Thread 在外面等
但因為沒有達成退出條件,所以就一直卡在 while
裡面,程序就進入永遠的循環
這就是所謂的 Deadlock
資料補充:Deadlock
修改 Deadlocks.java
import java.util.Random;public class Deadlocks {
public static void main(String[] args) {
Message message = new Message();
(new Thread(new Writer(message))).start();
(new Thread(new Reader(message))).start(); }
}class Message {
private String message;
private boolean empty = true; public synchronized String read() {
while (empty) {
try {
wait();
} catch (InterruptedException e) { }
}
empty = true;
notifyAll();
return message;
} public synchronized void write(String message) {
while (!empty) {
try {
wait();
} catch (InterruptedException e) { }
}
empty = false;
this.message = message;
notifyAll(); }
}class Writer implements Runnable {
private Message message; public Writer(Message message) {
this.message = message;
} public void run() {
String messages[] = {
"Humpty Dumpty sat on a wall",
"Humpty Dumpty had a great fall",
"All the king's horse and all the king's men",
"Couldn't put Humpty together again."
}; Random random = new Random(); for (int i = 0; i < messages.length; i++) {
message.write(messages[i]);
try {
Thread.sleep(random.nextInt(2000));
} catch (InterruptedException e) { }
}
message.write("Finished"); }
}class Reader implements Runnable {
private Message message; public Reader(Message message) {
this.message = message;
} public void run() {
Random random = new Random();
for (String latestMessage = message.read(); !latestMessage.equals("Finished");
latestMessage = message.read()) {
System.out.println(latestMessage);
try {
Thread.sleep(random.nextInt(2000));
} catch (InterruptedException e) { }
}
}
}
輸出結果:
Humpty Dumpty sat on a wall
Humpty Dumpty had a great fall
All the king’s horse and all the king’s men
Couldn’t put Humpty together again.
因此這邊使用了 wait()
跟 notifyAll()
來解決此問題
前者可以當作是先在這邊暫停並等待喚醒而後者就是喚醒前者
一開始沒有使用這兩者的時候,程序卡在 read()
裡面
當第二次 for
的時候,因為第一次已經把 empty
改成 true
了
也沒有外力可以改變,所以就卡死在那邊
當這次使用了這兩者,就變成到 wait()
之時,先暫停執行並解鎖,好讓程序繼續執行
而此時 write()
那邊,因為可以繼續往下走就把 empty
改成 false
了
之後又走到 notifyAll()
把 read()
那邊喚醒
此時一看 empty
已經改變就順利跳出 while
了,所以不會繼續卡死在那邊