Java锁机制的理解(欢迎指正)

概述

两种加锁的方式:

1.synchronized关键字

2.使用Lock接口的实现类,例如:ReentrantLock(可重入锁)、ReadLock(读锁)、WriteLock(写锁)

首先介绍一个重要的概念:

CAS:即比较并设置,这个操作是原子的。首先进行比较,如果原值要进行更改,再更改之前会比较原值是否发生过改变,如果没有的话就会执行更改,如果发生过改变,就不会进行更改。

一、乐观锁和悲观锁(宏观分类)

从宏观角度,将锁分为了两类

乐观锁:读取数据的时候,认为数据没有被修改,不会加锁。如果要更新数据的话,会检查从读取到要更新这段时间里,数据是否有改变,如果有,就重新读取,再次尝试更新,再次进行检查。适用于写操作比较少的情况。

悲观锁:读取数据的时候,认为数据会被修改。每次读取数据的时候都会上锁,其他线程要读取的话直接被阻塞。

二、synchronized锁升级(偏向锁-轻量级锁-重量级锁)

在JDK1.6之前,synchronized会直接加重量级锁。

JDK1.6之后,对synchronized锁机制进行了优化,synchronized会有从无锁到偏向锁,再到轻量级锁,最后转变为重量级锁的升级过程,且只能按照该顺序升级,不允许降级。下面来简要描述一下该过程:

1、初次执行到synchronized代码块的时候,锁对象会转为偏向锁,执行完同步代码块中的代码,线程不主动释放锁。当第二次执行到这个代码块的时候,会校验当前线程是否为持有锁的线程,如果是的话,代码继续执行。由于刚才没有主动释放锁,也就不需要重新加锁了。

2、当发生锁竞争的时候,偏向锁转为轻量级锁。

首先解释一下锁竞争:一个线程持有锁,没有释放,另一个线程尝试获取锁,发现锁已经被占用了,发生了锁等待,这就锁竞争。

轻量级锁:轻量级锁是一个自旋锁。当发生锁竞争后,一个线程持有锁,另一个线程会进入自旋状态。会不断尝试获取锁,直到持有锁的线程将它释放。获取锁,就是通过CAS修改对象头信息里的锁标志位。比较锁标志位为"释放",然后尝试更改为"锁定",如果更改成功,就说明拿到锁了。

3、当一个线程的自旋次数达到一个值(该值可通过JVM参数设置,默认是10)。线程会把轻量级锁转为重量级锁,当其他线程尝试获取锁的时候,发现该锁为重量级锁,会直接挂起,然后等待唤醒。

三、可重入锁(ReentrantLock)

可重入锁即允许同一线程多次获取同一把锁。可重入锁又叫递归锁。

四、公平锁和非公平锁

公平锁:多个线程获取同一把锁,先获取的会先拿到锁。

非公平锁:多个线程获取同一把锁,可能后尝试获取的线程会先拿到锁。

synchronized:非公平锁

五、读写锁

读写锁是一对锁。

读锁:如果获取的数据的时候发现锁是读锁,就直接获取,然后计数器+1,不会发生锁等待。我们在加锁的时候,如果这部分数据只是为了展示,而不会有修改的操作,就加读锁,提高了效率。

写锁:和读锁相反,如果发现锁是写锁,线程就会等待锁的释放。

读写锁属于悲观锁,并不属于乐观锁。乐观锁的概念,相当于"无锁",读写锁只是在加锁的前一步,决定了使用锁的类型。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值