文章目录
在讨论锁相关概念和原理之前,我们先来了解一下线程安全的问题,线程安全主要有以下两方面影响:
1.操作中存在临界资源,也称共享资源。
2.系统中存在多线程操作临界资源。
常见的解决方案:
当系统中存在多个线程操作临界资源时,我们需要保证线程之间的共享资源可见,当其中一个线程获取到操作共享资源的权利后,会对该资源进行加锁限制,防止其它线程再对该资源进行修改,当该线程操作完后,会释放资源锁。
悲观锁VS乐观锁
在并发操作中,为了实现线程之间的资源共享,保证数据的一致性,通常需要进行线程间数据同步,在java中同步有很多种方式,其中 synchronized 是最常见的一种实现资源同步的方式,对资源进行加锁。接下来我们首先研究下 悲观锁和乐观锁。简单总结如下图所示:
1.悲观锁
1.1什么是悲观锁
悲观锁:线程进行并发操作时,总是以最坏的情况进行操作,假设总有其它线程会对资源进行更新,所以,当线程获取到资源时,会对资源进行加锁操作,避免其它线程对资源进行更新,等待当前线程操作完后,会释放锁,此时其它线程可以获取资源,并完成相应的操作。
1.2源码分析
synchronized
synchronized 关键字在java中使用很频繁,使用该关键字可以资源进行加锁,本质上采用抢占式获取锁的机制,是一种典型的悲观锁。synchronized 也是一种互斥锁。关于互斥锁将在后续文章中做出说明。
- 三种应用方式
实例方法块
静态方法块
代码块
- 底层原理
- java虚拟机对synchronized的优化
- 关注点
Lock
1.3应用场景
悲观锁应用场景:
并发访问中存在频繁更新数据操作。
1.4实现
2乐观锁
2.1什么是乐观锁
乐观锁:线程进行并发操作时,总是以最好的情况进行操作,假设没有其它线程会对资源进行操作,如果当前线程只是进行查询操作,那么获取到当前最新的数据返回给接口即可,【至于这个共享资源在获取过程中会被其它线程更改,获取到的资源可能不是最新的,导致出现这个问题应该归于其它线程更新共享资源的一种机制】。如果当前线程需要对共享资源进行更新操作,那么常常会采用一种校对更换的机制,即 CAS(Compare And Swap)。CAS原理将在下面进行介绍。
2.2源码分析
CAS 原理
cas是一种无锁机制,在不使用锁的情况下实现多线程之间的资源共享,cas中有三个值:需要读写的内存值V,需要进行比较的值A,需要更新的值B(需要写入内存)。
当且仅当V == A时,才会进行更新操作V=B(将V值替换为B),更新操作是一个不断重试的机制,如果不满足V==A,会一直重试,直到满足后作更新操作。
CAS 问题
- ABA问题
- 更新重试操作耗资源
- 只能对一个变量作原子操作
2.3应用场景
并发访问中存在频繁查询数据操作
2.4实现
总结
悲观锁是一种抢占式锁,获取资源后,对资源进行加锁,保证只有当前线程可进行操作,其它线程继续阻塞,等待当前线程处理完释放锁后,才可进行资源争夺。悲观锁适合于频繁更新的操作,比如数据库更新时表锁等。
乐观锁实际上并未对共享资源进行加锁,而是采用比较更新的(cas)机制,保证多线程之间共享资源的一致性。更新操作是一个不断重试的操作。乐观锁适合于频繁查询的操作。
未完待续…