package com.sunle.thread;
import java.util.ArrayList;
import com.sunle.object;
/**
* 死鎖:
* 就是兩個同時在運行的線程,他們在擁有自己的對象同時,又要互相訪問資源。
* 這時同步機制就發揮了作用,導致它們都開始等待對方先執行完,而雙方都要做的
* 卻是訪問對方鎖定的資源,這樣就進入了線程死衚衕。
*
*
* 1.利用多線程在同步關鍵字synchronized()鎖定容器ArrayList對象,
* 在進行增加和移除時出現的死鎖問題。
*
* 2.針對問題1,用代碼將它問題結果最直觀的展現出來。
*
* 3.通過結果顯示得出結論:當多個同步鎖同時鎖住一個對象的情況下,
* 會出現
* @author 孫樂
*
*/
public class SynDeadLockT {
public static void main(String[] args){
ArrayList arr1;
ArrayList arr2;
arr1=new ArrayList<>();
arr2=new ArrayList<>();
Test t=new Test();
t.setArrA(arr1);
t.setArrB(arr2);
Thread th1=new Thread(t,"--th1--");
Thread th2=new Thread(t,"--th2--");
th1.start();
th2.start();
}
}
class Test implements Runnable{
private ArrayList arrA;
private ArrayList arrB;
private String str1="--th1--";
private String str2="--th2--";
int j=0;
public ArrayList getArrA() {
return arrA;
}
public void setArrA(ArrayList arrA) {
this.arrA = arrA;
}
public ArrayList getArrB() {
return arrB;
}
public void setArrB(ArrayList arrB) {
this.arrB = arrB;
}
public void run(){
arrAdd();
arrDel();
}
//ArrayList增加數據方法,利用同步鎖,鎖住了操作對象的代碼塊
private void arrAdd(){
synchronized (arrA) {
//1t,2t
System.out.println(str1.equals(Thread.currentThread().getName()));
System.out.println(str2.equals(Thread.currentThread().getName()));
//arrB添加數據代碼塊,根據先後進入的線程,對容器對象進行添加數據的控制。
for(int i=0;i<5;i++){
if(j==5&&j<6){
/*如果打印的是1表示已經new了一個新的容器對象,並且容器裏面沒有數據。
* 並且CPU已經執行完了前面的線程,釋放了之前地址,JVM回收了之前的收對象*/
/*1.若打印的是地址,並且和下面del方法出現的是同一個地址,
* 那麼證明CPU尚未執行完前線程一,只是cpu分配給線程一的
* 時間片段已經用完,線程一的狀態是等待cpu再次運行時間片,
* 這時線程二開始了它的執行。
*
* 2.這時線程一和線程二都擁有調度arrA和arrB的權限,只是
* 這時的線程一已經執行到刪除方法在等CPU,線程一鎖住的對象arrB裏還含有
* 另一個同步對象arrA的鎖,正好線程二正在調度的是arrA的同步鎖,
* 而線程二里也有arrB的同步鎖
*
* 3.接下來當線程二執行將要調度arrB時,發現線程一還未執行完arrB,那麼
* 線程二就開始等待線程一執行完,
* 接着線程一便開始執行,但是當它執行到arrA時,又發現線程二還未
* 執行完arrA,這時線程一也開始了等待,兩個線程就開始了漫長的互相等待*/
System.out.println("add方法監聽A的地址1:"+arrA.hashCode()+Thread.currentThread().getName());
}
arrA.add(Thread.currentThread().getName());
if(str1.equals(Thread.currentThread().getName())&&arrA.size()>5){
System.out.println(arrA.get(arrA.size()-i-1)+"添加方法A");
}else if(str2.equals(Thread.currentThread().getName())&&arrA.size()>5){
System.out.println(arrA.get(arrA.size()-i-1)+"添加方法A");
}else{
if(j==5){
//如果不是同一個對象,這裏將打印新對象的地址,程序就不會死鎖。
System.out.println("Add方法監聽A的地址2:"+arrA.hashCode()+Thread.currentThread().getName());
}
System.out.println(arrA.get(i)+"添加方法A");
}
j++;
}
System.out.println(arrA.size()+"容器長度---J="+j);
synchronized (arrB) {
//arrB添加數據,和arrA添加數據是一個模型
for(int i=0;i<5;i++){
arrB.add(Thread.currentThread().getName());
if(str1.equals(Thread.currentThread().getName())&&arrB.size()>5){
System.out.println(arrB.get(arrB.size()-i-1)+"添加方法B");
}else if(str2.equals(Thread.currentThread().getName())&&arrB.size()>5){
System.out.println(arrB.get(arrB.size()-i-1)+"添加方法B");
}else{
System.out.println(arrB.get(i)+"添加方法B");
}
}
}
}
}
//ArrayList移除數據方法,利用同步鎖,鎖住了操作對象的代碼塊
public void arrDel(){
synchronized(arrB){
/*監聽容器arrA在上一個方法增加完數據之後,在本移除方法裏即將執行synchronied代碼塊
* 之前打印的容器arrA的地址,它打印的是按CPU先後順序執行的線程。-----下面註釋提示----*/
System.out.println("Del方法監聽A的地址:"+arrA.hashCode()+Thread.currentThread().getName());
for(int i=0;arrB.size()>0;i++){
System.out.println(arrB.get(arrB.size()-1)+Thread.currentThread().getName()+"刪除B");
arrB.remove(arrB.size()-1);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*-------------上一個註釋,指的是這裏-----------爲直觀展示---------*/
synchronized(arrA){
for(int i=0;arrA.size()>0;i++){
System.out.println(arrA.get(arrA.size()-1)+Thread.currentThread().getName()+"刪除A");
arrA.remove(arrA.size()-1);
}
}
}
}
}