关于死锁--

1.不可重入锁

什么是不可重入锁呢?

对同一个对象连续加锁两次,如果没有发生死锁情况,就说明是可重入的,否则则不是

java是如何实现可重入锁的呢? 如果当前持有锁的线程和将加第二次锁的线程为同一个线程,即可以正常执行,否则阻塞

public class deadLoker {
    synchronized public void resyn(){
        for(int i = 0; i < 10; i++){
            synchronized (this){
                System.out.println(i);
            }
        }
    }
    public static void main1(String[] args) {
        //Java支持可重入锁
        //什么是可重入锁 --- 连续的synchronized
        deadLoker d = new deadLoker();
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            d.resyn();
        });
        t.start();
    }

2.相互获取对方的锁

想象以下场景  你和你朋友在餐厅吃饭 你习惯拿筷子吃 他习惯用勺子吃
这时你想试试用勺子吃是什么样子的  同时  你朋友也正好像试试用筷子吃是什么样的
但是你们双方都不愿意把自己用称手的工具给对方
这个时候就会产生死锁
public static void main(String[] args) {
        //死锁问题
        //想象以下场景  你和你朋友在餐厅吃饭 你习惯拿筷子吃 他习惯用勺子吃
        //这时你想试试用勺子吃是什么样子的  同时  你朋友也正好像试试用筷子吃是什么样的
        //但是你们双方都不愿意把自己用称手的工具给对方
        //这个时候就会产生死锁
        Object loker1 = "chopstick";
        Object loker2 = "spoon";
        
        Thread t1 = new Thread(() -> {
            // 我拿到了自己称手的工具 --- 筷子
            synchronized (loker1){
                try {
                    //确保让朋友先拿到勺子
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (loker2){
                    System.out.println("我想试试用勺子吃");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            //朋友拿到了勺子
            synchronized (loker2){
                //确保让我拿到筷子
                try {
                    Thread.sleep(100);
                    synchronized (loker1){
                        System.out.println("我想试试用筷子吃饭是怎么样的");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }

在cmd命令控制行输入jconsole可以查看线程的相关状态,从上图我们可以看出两个线程都处于阻塞状态


3.哲学家就餐问题

问题描述:有5个哲学家绕着一张圆桌子吃饭,共有五支筷子,每个哲学家都拿了一个筷子放到左手上,由于吃饭需要一双筷子,所以右手还需要一支筷子才能完成吃饭操作,但正好这时筷子都被拿完了,哲学家们只好你看着我我看着你,都吃不了饭

仔细一思考,是不是和我们上面的那个例子很类似,只是对应的人数和对应的锁数增加了,其本质还是一样的,还是想要获取对方的锁来成全自己

解决思路:可以定义先后的吃饭顺序,给哲学家们排一个序,谁先吃,吃完释放筷子,这样就避免了每个人都只拿到一只筷子的情况,当然解决思路是多样的,只要破坏掉产生死锁的条件即可,那么产生死锁的条件有哪些呢?


4.产生死锁的条件

1.互斥使用:线程1拿到了锁对象,线程2就得等着直到线程1释放锁对象

2.不可抢占:线程1拿到锁对象后,必须是线程1主动释放锁,不能线程2强行获取线程1的锁对象

3.请求和保持:在线程1已经获得了锁A时,尝试再获得锁B时,不会由于已经有一把锁A了而释放掉锁A,而是继续保持锁A的状态

4.循环等待:线程1获得锁A并尝试获得锁B,线程2获得锁B并尝试获得锁A,线程1获取B时等待线程2释放B,线程2获取A时等待线程1释放A

看似有四个条件,其实我们的关键字synchronized就已经帮我们解决好了前三个,所以最主要的就是第四个条件-----循环等待


5.解决死锁的方法

要想解决死锁,无非就是破坏满足死锁的条件-----循环等待

那么我们就可以给锁对象排序,并让线程遵守从小到大的规则来加锁

(相互获取对方的锁)来举例,我们规定用筷子的人先使用勺子

 public static void main(String[] args) {
        Object loker1 = "chopstick";
        Object loker2 = "spoon";

        Thread t1 = new Thread(() -> {
            // 我拿到了自己称手的工具 --- 筷子
            synchronized (loker1){
                try {
                    //确保让朋友先拿到勺子
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (loker2){
                    System.out.println("我把筷子和勺子都拿到了");
                }
            }
        });

        Thread t2 = new Thread(() -> {
            //朋友拿到了勺子
            synchronized (loker1){
                //确保让我拿到筷子
                try {
                    Thread.sleep(100);
                    synchronized (loker2){
                        System.out.println("朋友把筷子和勺子都拿到了");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }

这样子,死锁问题好像就迎刃而解了~

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值