當業務比較複雜,多線程應用裏有可能會發生死鎖
死鎖產生的原因
- 線程1 首先佔有對象1,接着試圖佔有對象2
- 線程2 首先佔有對象2,接着試圖佔有對象1
- 線程1 等待線程2釋放對象2
- 與此同時,線程2等待線程1釋放對象1
就會。。。一直等待下去,直到永遠循環下去。
代碼演示形成死鎖
package multiplethread;
import charactor.Hero;
public class TestThread5 {
public static void main(String[] args) {
final Hero ahri = new Hero();
ahri.name = "九尾妖狐";
final Hero annie = new Hero();
annie.name = "安妮";
Thread t1 = new Thread(){
public void run(){
//佔有九尾妖狐
synchronized (ahri) {
System.out.println("t1 已佔有九尾妖狐");
try {
//停頓1000毫秒,另一個線程有足夠的時間佔有安妮
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("t1 試圖佔有安妮");
System.out.println("t1 等待中 。。。。");
synchronized (annie) {
System.out.println("do something");
}
}
}
};
t1.start();
Thread t2 = new Thread(){
public void run(){
//佔有安妮
synchronized (annie) {
System.out.println("t2 已佔有安妮");
try {
//停頓1000毫秒,另一個線程有足夠的時間佔有暫用九尾妖狐
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("t2 試圖佔有九尾妖狐");
System.out.println("t2 等待中 。。。。");
synchronized (ahri) {
System.out.println("do something");
}
}
}
};
t2.start();
}
}
藉助tryLock 解決死鎖問題
當多個線程按照不同順序佔用多個同步對象的時候,就有可能產生死鎖現象。
死鎖之所以會發生,就是因爲synchronized 如果佔用不到同步對象,就會苦苦的一直等待下去,藉助tryLock的有限等待時間,解決死鎖問題
package multiplethread;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestThread13 {
public static void main(String[] args) throws InterruptedException {
Lock lock_ahri = new ReentrantLock();
Lock lock_annie = new ReentrantLock();
Thread t1 = new Thread() {
public void run() {
// 佔有九尾妖狐
boolean ahriLocked = false;
boolean annieLocked = false;
try {
ahriLocked = lock_ahri.tryLock(10, TimeUnit.SECONDS);
if (ahriLocked) {
System.out.println("t1 已佔有九尾妖狐");
// 停頓1000秒,另一個線程有足夠的時間佔有安妮
Thread.sleep(1000);
System.out.println("t1 試圖在10秒內佔有安妮");
try {
annieLocked = lock_annie.tryLock(10, TimeUnit.SECONDS);
if (annieLocked)
System.out.println("t1 成功佔有安妮,開始啪啪啪");
else{
System.out.println("t1 老是佔用不了安妮,放棄");
}
} finally {
if (annieLocked){
System.out.println("t1 釋放安妮");
lock_annie.unlock();
}
}
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
if (ahriLocked){
System.out.println("t1 釋放九尾狐");
lock_ahri.unlock();
}
}
}
};
t1.start();
Thread.sleep(100);
Thread t2 = new Thread() {
public void run() {
boolean annieLocked = false;
boolean ahriLocked = false;
try {annieLocked = lock_annie.tryLock(10, TimeUnit.SECONDS);
if (annieLocked){
System.out.println("t2 已佔有安妮");
// 停頓1000秒,另一個線程有足夠的時間佔有安妮
Thread.sleep(1000);
System.out.println("t2 試圖在10秒內佔有九尾妖狐");
try {
ahriLocked = lock_ahri.tryLock(10, TimeUnit.SECONDS);
if (ahriLocked)
System.out.println("t2 成功佔有九尾妖狐,開始啪啪啪");
else{
System.out.println("t2 老是佔用不了九尾妖狐,放棄");
}
}
finally {
if (ahriLocked){
System.out.println("t2 釋放九尾狐");
lock_ahri.unlock();
}
}
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
if (annieLocked){
System.out.println("t2 釋放安妮");
lock_annie.unlock();
}
}
}
};
t2.start();
}
}