Java 死锁 哲学家就餐问题解决


多锁

只有一个对象锁的话,程序的并发度很低(加synchornized 串行执行程序了)

我们可以准备多个对象锁,将锁的粒度细分

  • 好处 增强并发度

  • 坏处 如果一个线程需要同时获得多把锁,就容易发生死锁

1 死锁

一个线程需要同时获取多把锁,这时容易发生死锁

t1 线程 获得A对象锁,接下来想获取B对象的锁

t2 线程获得B对象锁,接下来向获取A对象锁

// 线程1 需要获取多把锁
      new Thread(()->{
          synchronized (a){
              log.debug("获得了A锁");
              synchronized (b){
                  log.debug("获得了B锁");
              }
          }
      }).start();

    // 线程2 需要获取多把锁
        new Thread(()->{
            synchronized (b){
                log.debug("获得了b锁");
                synchronized (a){
                    log.debug("获得了a锁");
                }
            }
        }).start();
    }

2 定位死锁

可以使用 jconsole 或者使用 jps 定位进程id,再用jstack定位死锁

jconsole中有检测死锁功能

使用jps查看进程id,jstack查看信息

在展示的信息中,它会给你列出 出现死锁的线程

3 哲学家就餐问题

是一个会导致死锁问题的经典场景,当哲学家们各拿起一个筷子,就会陷入死锁阶段:可以将筷子认为锁资源,哲学家认为是线程

解决方案:使用ReentrantLock的超时锁
当在规定时间内获取不到锁时,放弃竞争,并主动释放自身的锁
筷子类

//就餐所使用的筷子
class Chopstick2 extends ReentrantLock {
    String name;

    public Chopstick2(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Chopstick{" +
                "name='" + name + '\'' +
                '}';
    }
}

哲学家类

//哲学家
class Philosopher2 extends  Thread{
    Chopstick2 left;
    Chopstick2 right;
    public Philosopher2(String name,Chopstick2 left, Chopstick2 right) {
        super(name);
        this.left = left;
        this.right = right;
    }
    private void eat(){
        log.debug("eat ting");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while(true){
            //  尝试获取左手筷子
            if(left.tryLock()){
                //加锁成功
                try{
                    //临界区
                    //尝试获取右手筷子
                    if(right.tryLock()){
                        try{
                            eat();
                        }finally {
                            right.unlock();
                        }
                    }
                }finally {
                // 释放自身的锁
                    left.unlock();
                }
            }
        }
    }
}

调用

        Chopstick2 c1 = new Chopstick2("1");
        Chopstick2 c2 = new Chopstick2("2");
        Chopstick2 c3 = new Chopstick2("3");
        Chopstick2 c4 = new Chopstick2("4");
        Chopstick2 c5 = new Chopstick2("5");
        new Philosopher2("苏格拉底", c1, c2).start();
        new Philosopher2("柏拉图", c2, c3).start();
        new Philosopher2("亚里士多德", c3, c4).start();
        new Philosopher2("赫拉克利特", c4, c5).start();
        new Philosopher2("阿基米德", c5, c1).start();
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值