13 死锁

线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源。

public class Demo{
    private static Object resource1 = new Object();
    private static Object resource2 = new Object();
    public static void main(String[] args){
        new Tread(
            ()->{
                synchronized (resource1){
                    //do something
                    try{
                        Thread.sleep(1000);//为了让线程2得到执行
                    }catch(Exception e){
                        //do something
                    }
                    synchronized(resource2){
                        //do something
                    }
                }
            },"线程1"
        ).start();
        
         new Tread(
            ()->{
                synchronized (resource2){
                    //do something
                    try{
                        Thread.sleep(1000);//为了让线程1得到执行
                    }catch(Exception e){
                        //do something
                    }
                    synchronized(resource2){
                        //do something
                    }
                }
            },"线程2"
        ).start();
    }
}

死锁四个条件
1.互斥:资源只能由一个线程持有
2.保持:阻塞时,保持持有已有资源
3.不剥夺:没有权利剥夺其他线程持有的资源,只能资源释放
4.循环:若干线程之间形成头尾相接的循环等待

如何预防死锁
1.破坏保持:一次性申请所有资源
2.破坏不剥夺:
3.破坏循环:按序申请资源

//将线程2的代码改成这样,按资源1 资源2的顺序获取,就不会死锁了
  new Thread(() -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread() + "get resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                }
            }
        }, "线程 2").start();

sleep和wait的区别
sleep 不释放锁,自动苏醒
wait 释放锁,需要等别的线程调用notify 或notifyall,或者用wait(时间)

调start时会自动调run,为什么不能直接调run
new一个新线程,线程进入新建状态,调用start方法,会启动一个线程并使线程进入就绪状态,分配到时间片就可以运行了,start会执行线程的准备工作,然后自动执行run方法的内容。
直接调run方法,只是执行了呀一个普通方法,没有在某个线程中执行他,不是多线程工作。

你可能感兴趣的:(java)