锁的分类详解

本文探讨了并发编程中的死锁现象,通过羽毛球案例解释其形成条件。随后介绍了活锁,即线程互相等待对方释放资源导致无限循环,以及饥饿问题,由线程优先级低导致无法获取CPU资源。讨论了这些现象的示例和检测方法,重点在于理解它们在信息技术中的应用和解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、死锁

所谓死锁,就是多个线程竞争相同资源引起的。

举个例子,打羽毛球需要两样东西,羽毛球(锁对象A)和羽毛球拍(锁对象B)。现在有两个人(两个进程),其中一个人有羽毛球拍没有羽毛球,另一个人有羽毛球没有羽毛球拍;他们两个人都在等待另一样打羽毛球的必需品,于是都各各自等待,谁也不能打羽毛球。

(借用网上大佬的图片)

这就是死锁出现的条件 

下面是仿照别的大佬的死锁示例

    static Object o1 = new Object();
    static Object o2 = new Object();
    public static void main(String[] args){
        Thread t1 = new Thread(){
            @Override
            public void run(){
                synchronized (o1){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("t1 ---get o1");
                }
                synchronized (o2){
                    System.out.println("t1 ---get o2" );
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run(){
                synchronized (o2){
                    System.out.println("t2---get o2");
                    synchronized (o1){
                        System.out.println("t2 get o1");
                    }
                }
            }
        };
        t1.start();
        t2.start();
    }

死锁的产生就是由于t1线程一开始占有o1,t2线程此时占有o2,t1线程进行中想要获得o2对象锁,而同时t2线程想要获得o1对象锁。但由于两个对象锁此时均被占有,所以线程必须一直等待,导致死锁。

定位死锁

检测死锁可以使用jconsole工具,或者使用jps定位进程id,在使用jstack定位死锁。

二、活锁 

活锁出现在两个线程相互改变对方的结束条件,最后谁也无法结束

    static Object o1 = new Object();
    static volatile int count = 10;
    public static void main(String[] args){
        new Thread(()->{
            while (count>0){
                try {
                    Thread.sleep(1);
                    count--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(()->{
            while (count<20){
                try {
                    Thread.sleep(1);
                    count++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

该情况就是非常典型的活锁状态导致永远无法退出线程。

第一个线程的结束条件是count<0,并在循环中进行自减操作;第二个线程结束条件是count>20,并在循环中进行自加操作。但由于两个线程并发控制同一volatile变量(可见性保证),导致自加和自减操作交替进行,两个线程永远无法退出。

注意,这里使用volatile生命变量,若不使用volatile,则不一定会出现活锁现象,因为volatile具有可见性,即任何一个线程对变量的改变其他线程均可见。

三、饥饿 

一个线程由于优先级太低,始终得不到 CPU 调度执行,也不能够结束。

饥饿是由于线程本身优先级问题导致的,在读写锁处容易产生。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值