分布式与高并发-2-Synchronized

本文详细介绍了Java中的锁机制,包括实例锁、类锁(类对象锁)、代码块锁以及锁的升级过程。实例锁针对单个对象实例,类锁针对所有对象实例,而代码块锁可以自定义锁定范围。Java 1.6后的锁优化策略,如偏向锁、轻量级锁和重量级锁,旨在提高无锁竞争时的效率,减少线程阻塞带来的性能开销。锁升级策略确保在有竞争时能平滑过渡到更高级别的锁,以保证线程安全。
摘要由CSDN通过智能技术生成

1、实例锁

1.1、代码
public class SynchronizedTest {
    synchronized void demo1(){
        //等价于synchronized(this) 是对这个类的实例进行加锁
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":"+DateTimeUtils.getCurrDateTime());
    }

    //与demo1等价
    void demo2(){
        synchronized (this){
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+DateTimeUtils.getCurrDateTime());
        }
    }
    
    public static void main(String[] args) {
        SynchronizedTest test1=new SynchronizedTest();
        //实例锁
        new Thread(()->test1.demo1(),"demo1").start();
        new Thread(()->test1.demo1(),"demo2").start();


        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SynchronizedTest test2=new SynchronizedTest();
        SynchronizedTest test3=new SynchronizedTest();

        new Thread(()->test2.demo1(),"demo3").start();
        new Thread(()->test3.demo1(),"demo4").start();
    }
}

1.2、执行结果

在这里插入图片描述

1.3、结果分析
  1. demo1和demo2线程都是对test1实例进行抢占锁,存在互斥性,所以存在阻塞
  2. demo3和demo4是两个实例 test2和test3,所以不存在阻塞
  3. 只针对当前对象实例加锁,test1、test2、test3存在三个锁,因为这是三个实例

2、静态方法=类锁=类对象锁

2.1、代码
public class SynchronizedTest {
    synchronized static void demo1(){
        //等价于synchronized(this) 是对这个类的实例进行加锁
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+":"+DateTimeUtils.getCurrDateTime());
    }

    //与demo1等价
    void demo2(){
        synchronized (SynchronizedTest.class){
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":"+DateTimeUtils.getCurrDateTime());
        }
    }

    public static void main(String[] args) {
        SynchronizedTest test1=new SynchronizedTest();
        //类锁
        new Thread(()->test1.demo1(),"demo1").start();
        new Thread(()->test1.demo1(),"demo2").start();
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SynchronizedTest test2=new SynchronizedTest();
        SynchronizedTest test3=new SynchronizedTest();
        //类锁
        new Thread(()->test2.demo1(),"demo3").start();
        new Thread(()->test3.demo1(),"demo4").start();
    }
}
2.2、运行结果

在这里插入图片描述

2.3、结果分析
  1. 加在类上的锁,不管是不是一个实例,都会存在互斥性,进行锁竞争
  2. 类锁和对象锁 体现在互斥的范围
  3. 类锁:针对所有的对象都互斥

3、代码块锁

其实就是锁对象的应用范围

4、锁升级

4.1、 互斥锁的本质-> 共享资源
4.2、锁升级过程:由于加锁一定会带来性能开销,所以JDK1.6后做了锁优化,锁逐渐升级,ThreadA持有了偏向锁,ThreadB来抢占偏向锁,若在偏向锁内部的处理机制中,ThreadB不能抢占成功获得锁,则会升级到轻量级锁,如果轻量级锁中还没有获取到,则ThreadB在重量级锁中进行阻塞;
ThreadA
没有获得锁的线程怎么处理
ThreadA
偏向锁
轻量级锁
重量级锁
执行
释放之后
BLOCK状态排队
ThreadB
4.2.1、优化的目的?

在ThreadB线程阻塞前,获得锁;在不加锁的情况下解决线程安全问题

4.2.2、性能开销?

是线程的阻塞带来性能开销

4.3、偏向锁过程
  1. 线程1进入代码块后,获得偏向锁,并且线程1将同步块的互斥标记修改
  2. 在有线程1获得偏向锁的阶段,线程2访问代码块,会先检查对象头是否存储里线程2,如果没有则尝试CAS替换Mark-Word,如果替换不成功,则撤销原有偏向锁,然后进行锁升级(轻量级锁);如果替换成功则线程2获得偏向锁
    2.1、扩展:
    什么时候CAS替换成功,由线程2获得偏向锁呢?
    答:
    1》线程1已经执行结束
    2》已经升级到轻量级锁+
    3》已经是全局安全点,没有指令在操作
    什么时候开启轻量级锁?
    答:
    1》如果现成本身就存在竞争则不要开始轻量级锁->因为轻量级锁本身就是一种优化,目的是提升数据在没有竞争的时候的效率
    2》轻量级锁默认是关闭的
没有
成功
没有
不成功
线程1
访问同步块
检查对象头中是否存储了线程1
CAS替换mark-word
将对象头Mark-word中的线程id指向自己
执行同步体
暂停线程
解锁将线程ID设为空
去除线程1上之前添加的标记
线程1添加一个标记
线程2
访问代码块
检查对象头中是否存储了线程2
CAS尝试替换mark-word
撤销偏向锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值