深入理解Java锁---概念篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zl_1079167478/article/details/84102149

Java锁

什么是锁

多线程访问同一资源,对资源进行了非原子性操作,产生的并发安全问题。为了解决这种并发安全问题产生了锁

那么什么是并发安全问题?

参照数据库隔离级别来说简单一点

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
不可重复读(read-committed)
可重复读(repeatable-read)
串行化(serializable)

简单概括一下,就是指对资源的非原子性操作,会产生 脏读,幻读,不可重读的情况。

好,知道了什么是并发安全问题,那么就产生了锁来解决这种问题。那么锁分哪些呢?有什么区别呢?

锁分类(二类)

锁从宏观上分类,分为悲观锁与乐观锁。

  1. 乐观锁
    乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。
    java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。

  2. 悲观锁
    悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。

锁分类–功能区分

  • 可重入锁
  • 不可重入锁
  • 公平锁
  • 非公平锁
  • 自旋锁

我们之前说了,为什么会有锁,因为有并发安全问题,那么为什么有这么多种锁呢,那是因为并发安全问题又细分了好多,现在一一解释一下,为什么会产生上面的那些锁

可重入

什么是可重入? 简单说就是同一线程在持有锁的情况下,可以不释放锁连续访问该锁对象的其他同步方法,直白些就是,一个对象有N个方法,线程访问了A方法,获取到了锁,同时A方法调用了 对象的B方法,那么该线程就可以在不释放锁(意味着不需要再次竞争锁)的情况下访问B方法
公平锁
什么是公平? 就是按照先到先得的思路,比如排队打饭,谁先来就先给谁打饭,而不是大家一窝蜂抢,谁抢到就给谁打饭,那么那些瘦弱的小朋友岂不是要饿死,所以引入了公平的概念,线程也是这样。大家知道线程靠竞争获取CPU执行片段,从而获取锁。那么会不会出现极端情况,有个线程一直都竞争不到,那么那个线程岂不是废了。所以这里引入了公平锁的概念

自旋锁

什么是自旋? 为什么要自旋? 因为JVM 认为在多数情况下,锁一般是只由一个线程在使用,那么线程使用完毕之后释放掉,下次还是这个线程又来了,还要在重新获取锁,是个问题,那么怎么办呢? 就是线程在获取锁,执行完毕之后,不释放锁,一直占有,等到有人要获取锁了它才释放,如果这个人还是他自己,那么他就无需再次竞争锁了,直接就进来执行了,这个概念是个优化概念,并不是问题、

好了,以上有个大概的认知,Java 中提供了以上所有的解决思路和类库。

猜你喜欢

转载自blog.csdn.net/zl_1079167478/article/details/84102149