锁的概念和synchronizated关键字

1. Java中锁的概念

锁类型描述
自旋锁为了不放弃CPU执行事件,循环地使用CAS技术对数据尝试进行更新,直至成功
悲观锁假定会发生并发冲突,同步所有对数据的相关操作,从读数据就开始上锁
乐观锁假定没有冲突,在修改数据时如果发现数据和之前获取的不一致,则读最新数据,修改后重试修改
独享锁(写)给资源加上写锁,线程可以修改资源,其他线程不能再加锁(单写)
共享锁(读)给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁(多读)
可重入锁、不可重入锁线程拿到一把锁之后,可以自由进入同一把锁所同步的其他代码
公平锁、非公平锁争抢锁的顺序,如果是按先来后到,则为公平
  • 几种重要的锁实现方式:synchronized、ReentrantLock、ReentrantReadWriteLock

2.同步关键字synchronized

  • 属于最基本的线程通信机制,基于对象监视器实现的

  • Java中的每个对象都与一个监视器相关联,一个线程可以锁定或解锁。

  • 一次只有一个线程可以锁定监视器

  • 试图锁定该监视器的任何其他线程都会被阻塞,直到它们可以获得该监视器上的锁定为止。

  • 特性:可重入、独享、悲观锁

  • 锁的范围:类锁、对象锁、锁消除、锁粗化,后两者可借助可视化开源工具 gitwatch 分析。

  • 提示:同步关键字,不仅是实现同步,根据JMM规定还能保证可见性(读取最新主内存数据,结束后写入主内存)。

3. JVM堆内存中的对象存储方式

在这里插入图片描述

  • 状态位标记该对象是否被锁定或者被锁定的级别。

4.同步关键字加锁原理

HotSpot中,对象前面会有一个类指针和标题,存储标识哈希码的标题字以及用于分代垃圾收集的年龄和标识位。默认情况下JVM锁会经历:偏向锁–>轻量级锁–>重量级锁这四个状态。

4.1多线程下对象锁的迭代变更

在这里插入图片描述

  • 线程-1发现对象的状态位处于未锁定状态,就改为00,给对象加上轻量级锁。
  • 此时线程-2也来获取对象了,发现对象被别的线程加上了轻量级锁,这时它利用CAS机制不断去尝试去锁定对象,就是利用了自旋锁的概念;考虑到CPU优化,后续改成了当自旋达到一定次数后,仍无法拿到对象,就将对象置于对象监视器(monitor)的等待集合中,并不断去争抢对象的持有权。
  • 此时锁就升级到了重量级锁。注意,重量级锁的生成,不是因为加锁的时间变长了,一方面因为存在线程的争抢,另一方面是因为重量级锁环境下,多了一个对象需要管理。这个对象就是对象监视器对象(monitor)。

4.2 偏向锁的加入

我们先来考虑这么一个问题:当一个线程访问一个对象时,此时这个对象没有被锁定,按照之前的逻辑,我们会给对象加一个轻量级锁。然而,后续都没有线程来争抢这个对象,也就是在单线程下,也给对象上了锁,考虑一下,会不会很影响性能呢?

在Java编程中,大多数情况下都是单线程执行,很少会有并发量。偏向锁的使用,正是为了优化这一问题。
在这里插入图片描述

  • 线程-1获取对象时,会将线程信息更新为自己,此时线程为未锁定状态。当线程-1第二次再来获取这个对象时,只需要确认线程信息是否是自己就可以了。
  • 当线程-1获取到对象,执行代码期间,线程-2来争抢对象了,那么此时会关闭偏向锁标志(默认开启),立马升级为轻量级锁。
  • 偏向锁的使用,使对象在单线程下处于无锁状态,是一种优化的手段。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值