Đây không phải là một nhiệm vụ phỏng vấn đơn giản nhất mà bạn có thể nhận được: trong dự án của tôi, nó đã làm tê liệt công việc của một nhóm trong cả ngày. Rất dễ dàng để làm cho chương trình của bạn dừng lại, nhưng rất khó để đưa nó đến trạng thái mà kết xuất luồng viết một cái gì đó như,
Found one Java-level deadlock:
=============================
"Thread-2":
waiting to lock monitor 7f91c5802b58 (object 7fb291380, a java.lang.String),
which is held by "Thread-1"
"Thread-1":
waiting to lock monitor 7f91c6075308 (object 7fb2914a0, a java.lang.String),
which is held by "Thread-2"
Java stack information for the threads listed above:
===================================================
"Thread-2":
at uk.ac.ebi.Deadlock.run(Deadlock.java:54)
- waiting to lock <7fb291380> (a java.lang.String)
- locked <7fb2914a0> (a java.lang.String)
- locked <7f32a0760> (a uk.ac.ebi.Deadlock)
at java.lang.Thread.run(Thread.java:680)
"Thread-1":
at uk.ac.ebi.Deadlock.run(Deadlock.java:54)
- waiting to lock <7fb2914a0> (a java.lang.String)
- locked <7fb291380> (a java.lang.String)
- locked <7f32a0580> (a uk.ac.ebi.Deadlock)
at java.lang.Thread.run(Thread.java:680)
Vì vậy, mục tiêu sẽ là để có được một bế tắc mà JVM sẽ coi là một bế tắc. Rõ ràng, không có giải pháp nào như
synchronized (this) {
wait();
}
sẽ hoạt động theo nghĩa đó, mặc dù chúng thực sự sẽ dừng lại mãi mãi. Dựa vào điều kiện cuộc đua cũng không phải là một ý kiến hay, vì trong cuộc phỏng vấn, bạn thường muốn thể hiện một thứ gì đó có hiệu quả rõ ràng, chứ không phải thứ gì đó nên hoạt động trong hầu hết thời gian.
Bây giờ, sleep()
giải pháp là ổn theo một nghĩa nào đó, thật khó để tưởng tượng một tình huống mà nó không hoạt động, nhưng không công bằng (chúng ta đang ở trong một môn thể thao công bằng, phải không?). Giải pháp của @artbristol (của tôi cũng giống nhau, chỉ là các đối tượng khác nhau làm màn hình) rất hay, nhưng dài và sử dụng các nguyên thủy đồng thời mới để đưa các luồng ở trạng thái phù hợp, điều này không thú vị lắm:
public class Deadlock implements Runnable {
private final Object a;
private final Object b;
private final static CountDownLatch latch = new CountDownLatch(2);
public Deadlock(Object a, Object b) {
this.a = a;
this.b = b;
}
public synchronized static void main(String[] args) throws InterruptedException {
new Thread(new Deadlock("a", "b")).start();
new Thread(new Deadlock("b", "a")).start();
}
@Override
public void run() {
synchronized (a) {
latch.countDown();
try {
latch.await();
} catch (InterruptedException ignored) {
}
synchronized (b) {
}
}
}
}
Tôi nhớ lại rằng synchronized
giải pháp -chỉ phù hợp với 11..13 dòng mã (không bao gồm nhận xét và nhập khẩu), nhưng vẫn chưa nhớ lại thủ thuật thực sự. Sẽ cập nhật nếu tôi làm.
Cập nhật: đây là một giải pháp xấu cho synchronized
:
public class Deadlock implements Runnable {
public synchronized static void main(String[] args) throws InterruptedException {
synchronized ("a") {
new Thread(new Deadlock()).start();
"a".wait();
}
synchronized ("") {
}
}
@Override
public void run() {
synchronized ("") {
synchronized ("a") {
"a".notifyAll();
}
synchronized (Deadlock.class) {
}
}
}
}
Lưu ý rằng chúng tôi thay thế một chốt bằng một màn hình đối tượng (sử dụng "a"
như một đối tượng).