為了測試java多線程死鎖
得到java多線程死鎖的直觀感覺,寫出以下測試代碼。
public class TestDeadLock
{
public static void main(String[] args)
{
A a=new A();
B b=new B(a);
a.set(b);
Thread t1=new Thread(a);
Thread t2=new Thread(b);
t1.start();
t2.start();
}
}
class A implements Runnable
{
public B b;
public void run()
{
while (true)
{
synchronized(this)
{
b.write();
}
}
}
public void write()
{
synchronized (this)
{
System.out.println("a write");
}
}
public void set(B b)
{
this.b=b;
}
}
class B implements Runnable
{
public A a;
public B(A a)
{
this.a=a;
}
public void write()
{
synchronized (this)
{
System.out.println("b write");
}
}
public void run()
{
while (true)
{
synchronized(this)
{
a.write();
}
}
}
}
1、代碼導讀
對象a使用獨立線程去調用對象b的方法。
對象b使用獨立線程去調用對象a的方法。
對象a在調用b的方法之前對自己加鎖,調用對象b后對對象b加鎖。
對象b在調用a的方法之前對自己加鎖,調用對象a后對對象a加鎖。
2、死鎖形成原因解讀
a首先鎖了自己,b鎖了自己,
a去拿b的鎖,發現b已經鎖定了,則等待b的鎖釋放
b去拿a的鎖,發現a已經鎖定,則等待a釋放。
就這樣a等b,b也等a,造成了死鎖的問題。
3、死鎖的必要條件
兩個或兩個以上的線程在活動
某個線程拿到了一個鎖以后,還想去拿第二個鎖,即鎖的嵌套
4、預防死鎖的編程規范和方法。
@1、如果某個對象拿到了自己的鎖,如果想要去拿另外對象的鎖,一定要先釋放自己的鎖。任何鎖嵌套都是不安全的
@2、加鎖的代碼塊,其中盡量不要去調用另外的方法。因為很難在子方法中施放鎖。如果需要調用到其他的方法,需確定該方法以及其子分支肯定不會申請本鎖以外的鎖。
@3、遇到鎖中必須調用其他鎖的情況,必須確定下個鎖對象中不會再回調。所有鎖調用都是拓撲序的。
@4、在生產者--消費者模型中,使用倉庫的概念使得生產者與消費者脫離,即生產者不會需要去拿消費者的鎖,消費者也不會去需要拿生產者的鎖。他們只需要去拿倉庫的鎖。