一篇说清楚synchronized的类锁、对象锁、方法锁、代码块锁和它们的阻塞情况、死锁由来。

文章详细阐述了Java中的锁机制,包括类锁(静态方法和类级别的synchronized代码块)和对象锁(非静态方法和对象级别的synchronized代码块)。类锁确保同一时间只有一个线程能访问类的特定方法,而对象锁则限制了对特定对象实例的同步访问。死锁是由于锁的嵌套和不同线程间锁获取顺序的不一致导致的,而阻塞则发生在线程尝试获取已被其他线程持有的锁时。

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

1、类锁

锁住一个类,这个类中的所有带有synchronized的方法使用同一个锁。

比如:

public class CLock{

        //静态方法锁,使用的是类锁。以下两个方法使用同一个类锁,不同线程访问这两个方法,需要遵循同步锁执行规则。

        public static synchronized void test(){

        }

        public static synchronized void test2(){

        }

        public void test3(){

                //非静态方法种的代码块,如果用.class类来加锁,也是类锁。和上面的静态方法使用同一个锁。

                synchronized(CLock.class){

                }

        }

}

2.对象锁

一个对象拥有一个锁,相同的类不同的对象有不同的锁。

public class CLock{

        //非静态方法锁,使用的是对象锁。相同的CLock实例test和test2使用的是同一个锁。不同实例的相同方法也不是用同一个锁。

        public  void synchronized  test(){

        }

        public void synchronized test2(){

        }

        public void test3(){

                //非静态方法种的代码块,如果用this来加锁,也是对象锁。和上面的非静态方法使用同一个锁。

                synchronized(this){

                }

        }

}

所以 CLock c1 =new CLock();CLock c2 =new CLock();

c1.test()和c1.test2()、c1.test3使用的是同一个锁。c1.test()和c2.test()使用的是不同的两个对象锁,所以不同的线程可以同时访问c1.test()和和c2.test()。

还有的情况是单独创建一个对象,用来加锁。

 比如以下所有方法的synchronized 的锁都不是同一个对象即都不是同一个锁。

public class CLock{

        private Object mLock = new Object();

       private  static Object mLock2 = new Object();

        public  void synchronized  test(){//具体每个CLock实例拥有他们自己的锁。

        }

        public static void synchronized test2(){//static方法使用类锁。

        }

        public void test3(){

                synchronized (mLock ){//mLock是一个实例,拥有不同的mLock也拥有不同的锁。

                }

        }

        public void test4(){

                synchronized (mLock2 ){//mLock2是一个静态变量,不同的CLock也是拥有同一个锁。

                }

        }

总之,synchronized 的锁是以对象头的形式存储记录的,所以锁只跟锁实例是不是同一个有关,只要使用同一个锁实例,他们就互斥、阻塞。

3.死锁

那么什么情况会出现死锁的情况呢?那就是锁嵌套并且,不同线程执行的锁顺序刚好倒过来。

public class A{

        private Object mLock = new Object();

        private Object mLock2 = new Object();

        public void test(){

                synchronized(mLock){

                         Thread.sleep(1000);

                        synchronized(mLock2 ){

                        }

                }

        }

        public void test2(){

                synchronized(mLock2 ){

                         Thread.sleep(1000);

                        synchronized(mLock​​​​​​​){

                        }

                }

        }

}

如果thread1执行 test1(),刚好thread2执行test2()。那么就会出现thread1占有mLock锁,需要访问mLock2锁,就需要等待thread2释放mLock2锁。而thread2占有mLock2锁,需要访问mLock锁,就要等待Thread1释放mLock锁。

        相当于是我先拿到你手中的梨才能给你苹果,而你一定要先拿到我手中的苹果才能给我梨。双方僵持不下,就死锁了。

4.阻塞

阻塞是从加锁的地方开始的,下面的代码中多个线程会直接访问a()方法,不需要考虑锁的问题,但是只要mLock被一个线程占有,那么其他线程也无法访问b()方法,都是阻塞在加锁位置,无法往下执行。

public class A{

        private Object mLock = new Object();

        public void test(){

                a();

                synchronized(mLock){

                ​​​​​​​         Thread.sleep(1000);

                 }

                b();

        }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闽农qq:994955138

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值