java中的线程死锁问题

文章介绍了Java中死锁的三种典型情况:互相依赖的线程加锁顺序、哲学家问题以及不可重入锁的问题。接着阐述了死锁产生的四个原因:不可抢占、请求和保持、互斥和循环等待。文章指出,在Java中,可以通过避免循环等待来防止死锁,方法是为锁编号并规定线程按编号顺序申请锁。
摘要由CSDN通过智能技术生成

死锁的三大典型情况

(1)两个进程互相都需要对对方已经加锁的对象进行加锁才能被唤醒,如:线程甲先对a加锁了,还需要对b进行加锁,线程乙先对b加锁了,还需要对a加锁,此时就陷入死锁状态,两个线程都无法对需要的对象进行加锁,出现了死锁

public satic void main(Stirng [] args){
    Object a=new Object();
    Object b=new Object();
    Thread t1=new Thread(()->{
        synchronized(a){
            synchronized(b){
                //线程t1先获取了a对象的锁,再获取b对象的锁
            }
        }
    });
    
    Thread t2=new Thread(()->{
        synchronized(b){
            synchronized(a){
                //线程t2先获取了b对象的锁,再获取a对象的锁
            }
        }
    });
    //当线程t1或者t2在获取到第一个对象的锁后,cpu跑去执行另一个线程,
    //此时就会产生死锁
}

(2)哲学家问题

一张桌子上坐着几个哲学家,每个哲学家两旁都分别放有一根筷子,哲学家平时思考问题,有时饿了就会从左右两边拿起两根筷子吃饭,当一种极限情况,所有的哲学家同时饿了开始吃饭,且都拿起了左边的筷子,此时哲学家就等到右边的筷子被释放,但是右边的筷子不可能被释放,因为每个哲学家都在等待筷子,没有人会释放

(3)不可重入锁

不可重入是指,对一个线程对一个对象加锁之后,在释放锁之前,又想对这个对象进行加锁,但是此时这个对象已经有锁了,就会陷入等待这个锁释放,但是第一个锁本身就是被线程本身加锁的,线程陷入了死锁,这个锁的特性就被称为不可重入锁,java的synchronized是可重入锁,不会出现这个问题

讲完上述的死锁的典型状况后,我们就需要来防止产生死锁,为了防止产生死锁,我们需要了解死锁产生的原因,死锁产生的原因有四个

(1)不可抢占

当一个线程获取到一个锁之后,另一个线程也想获取这个锁是不可抢占的,只能等待这个线程把锁释放才能获取到锁;

(2)请求和保持

当一个线程请求不到一个锁陷入等待后,不保持已经获得的锁,不释放

(3)互斥

一个锁每次只能被一个线程获取

(4)形成循环等待

各个线程的等待首尾相良,形成循环等待

在java中,前面三个条件是无法改变的,这是锁的特性,我们只能获取通过改变条件四来预防死锁的发生,为了防止条件4发生,我们将线程所有需要申请的锁都编个号,规定如果要申请锁只能从编号小的往编号大的申请,这样就能防止产生循环等待

为什么从编号小的往编号大的方向申请就能防止循环等待呢?

还是线程甲乙和锁ab,将锁a编号为1,锁b编号为2,此时甲乙都想申请锁a和b,他们需要现申请a,在申请b,只要甲线程申请到a,那b也只能被甲线程申请,因为乙必须先申请到a,才能申请b,而a已经被甲申请了,乙只能等待

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值