Java線程死鎖是由於有些資源彼此交叉取用,就有可能造成死結.
如1線程中 取得A對象的鎖定後又要取得B對象的鎖定.但是同時2線程中取得B對象的鎖定後又要取得A對象的鎖定.這兩個線程同時發生時就會造成,1線程拿到A對象鎖定後等待B對象的鎖定.2線程拿到B對象鎖定後等待A對象鎖定.這樣就會進入沒有停止的等待中.
線程死鎖的一個簡單例子:
package deadLockThread;
public class Test {
private int size=0;
public synchronized void doSome(){
size++;
}
public synchronized void doTest(Test test){
try {
Thread.sleep(1000);//睡眠1秒 效果更明顯
} catch (InterruptedException e) {
e.printStackTrace();
}
test.doSome(); //另外一個對象調用synchronized 函數 需要取得該對象的對象鎖定
}
}
package deadLockThread;
public class DeadLock {
public static void main(String[] args) {
final Test t1=new Test();
final Test t2=new Test();
Thread th1=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
t1.doTest(t2);
}
});
Thread th2=new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
t2.doTest(t1);
}
});
th1.start();
th2.start();
}
}
如果真的沒辦法避免資源的交叉取用 我的解決方法是使用並行API在取得第一個對象鎖定前先檢測另外一個對象的對象鎖定有沒有被其他的線程拿走了.
synchronized 要求線程必須取得對象鎖定,纔可以執行所標識的區塊範圍.然而使用synchronized 有許多的限制,未取得鎖定的線程會直接被打斷.所以我這裏使用並行API Lock 替代直接操作synchronized .
package deadLockThread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test {
private int size = 0;
private Lock lock = new ReentrantLock();
public void doSome() {
System.out.println(Thread.currentThread().getName() + "獲取size");
size++;
}
public void doTest(Test test) {
while (true) {
boolean myLock = this.lock.tryLock();// 嘗試取得當前對象的Lock鎖定
boolean testLock = test.lock.tryLock();// 嘗試取得被傳入得對象的Lock鎖定
try {
if (myLock && testLock) { //當兩個對象的Lock 都獲取到後再進行 操作
test.doSome();
break;
}
} finally {
if (myLock) {
this.lock.unlock();
}
if (testLock) {
test.lock.unlock();
}
}
}
}
}
package deadLockThread;
public class DeadLock {
public static void main(String[] args) {
final Test t1 = new Test();
final Test t2 = new Test();
Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
t1.doTest(t2);
}
});
Thread th2 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
t2.doTest(t1);
}
});
th1.start();
th2.start();
}
}
文字部門參考Java學習筆記