先明確幾點:
1、所有synchronized修飾的非靜態方法用的都是同一把鎖:實例對象本身
2、所有synchronized修飾的靜態方法用的都是同一把鎖:類對象本身
3、而對於同步塊,由於其鎖是可以選擇的,所以只有使用同一把鎖的同步塊之間纔有着競態條件
好了,請看如下代碼
class CsdnMain{
public static void main(String[] args){
List<Ipbean> ipbeanList=new ArrayList<>();//假設裏面已經有100個數據了
for (int i=0;i<3;i++){
Thread thread=new Thread(new Runnable(){
@Override
public void run() {
Csdn.filter(ipbeanList);
}
});
thread.start();
}
}
}
class Csdn{
public static List<Ipbean> tenders=new ArrayList<>();
public static synchronized void add(Ipbean ipbean){
tenders.add(ipbean);
}
public static synchronized void filter(List<Ipbean> ipbeanList) throws InterruptedException {
if (ipbeanList==null)return;
for (Ipbean ipbean:ipbeanList){
if ("http".equals(ipbean.getType().toLowerCase())){
Thread thread=new Thread(new Runnable(){
@Override
public void run() {
add(ipbean);
}
});
thread.start();
thread.join();
}
}
}
}
你覺得這個代碼能夠正常執行完畢嗎?
答案是:不一定
如果列表中的IP都不是走http協議的 那麼這個程序確實會正確執行完畢,但是如果有一個走http協議的 那就會出現死鎖
原因如下:
當某一個線程在執行filter時,如果滿足執行add的條件,那麼該線程會新建另外一個線程去執行add方法,那麼就出問題了,Csdn這個類對象鎖此時掛在"該線程"上,沒有被釋放,而在其內部創建去執行add方法的線程也需要Csdn這個類對象鎖,一個需要鎖,一個不放鎖,並且不放鎖的又需要要鎖的線程執行完畢才能繼續執行,死鎖就出現了。