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);
}
}
}
}
}