一、锁的状态

       JDK1.6之前,synchronized 还是一个重量级锁,是一个效率比较低下的锁。但是在JDK1.6后,JVM为了提高锁的获取与释放效率对synchronized 进行了优化,引入了偏向锁和轻量级锁,从此以后锁的状态就有了四种:无锁、偏向锁、轻量级锁、重量级锁。并且synchronized 锁的四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级,这四种锁的级别由低到高依次是:无锁 < 偏向锁 < 轻量级锁 < 重量级锁。

  偏向锁:偏向于第一个获得锁的线程。synchronized 默认开启偏向锁。

  轻量级锁(自旋锁):自旋锁就是让不满足条件的线程循环等待,而不是立即挂起。自旋锁默认4秒后开启。

  锁升级的过程:

二、锁的优缺点

优点缺点适用场景
偏向锁 加锁和解锁不需要额外的消耗,和执行非同步方法比仅存在纳秒级的差距。 如果线程间存在锁竞争,会带来额外的锁撤销的消耗。 适用于只有一个线程访问同步块场景。
轻量级锁 竞争的线程不会阻塞,提高了程序的响应速度。 如果始终得不到锁竞争的线程使用自旋会消耗CPU。 追求响应时间。同步块执行速度非常快。
重量级锁 线程竞争不使用自旋,不会消耗CPU。 线程阻塞,响应时间缓慢。 追求吞吐量。同步块执行速度较长。

三、锁的分类

1. 线程会不会锁住同步资源:乐观锁(提交更新时才检测)读多写少 效率高 与 悲观锁(修改数据之前把数据锁住)

  synchronized和实现了lock接口的锁都是悲观锁。

  悲观锁:synchronized、ReentrantLock、ReenTranReadWriteLock

  乐观锁:CAS、StampedLock

2. 根据加锁的粒度:类级锁、对象锁、分段锁和单个变量/字段加锁
  2.1 类级锁:synchronized
  2.2 对象锁:synchronized
  2.3 分段锁:ConcurrentHashMap:jdk 1.8使用了Node + cas + synchronized实现了加锁。
  2.4 单个变量/字段加锁:使用CAS和java中原子引用类,通过保证编发编程中原子性,实现数据安全同步更新。

3. 根据锁的兼容性:独占锁共享锁

  独占锁:synchronized、ReentrantLock、ReenTranReadWriteLock中的WriteLock

  共享锁:ReenTranReadWriteLock中的ReadLock

独占锁也叫排它锁,是指该锁一次只能被一个线程所持有。如果别的线程想要获取锁,只有等到持有锁线程释放

获得排它锁的线程即能读数据又能修改数据,与之对立的就是共享锁。

共享锁:共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁

获得共享锁的线程只能读数据,不能修改数据。

4. 多个资源竞争时要不要排队:公平锁(排队)与非公平锁(不排队)

  公平锁:ReentrantLock、ReenTranReadWriteLock可公平可不公平

  非公平锁:synchronized

5. 一个线程中多个流程能不能获得同一把锁:重入锁与不可重入锁

  重入锁:synchronized、reentrantLock。是指同一个线程可以重入上锁的代码段,不同的线程进入则需要进行阻塞等待。

  不可重入锁:是指同一个线程不可以重入上锁后的代码段。

6. 锁同步资源失败是否需要阻塞:自旋锁(不阻塞)与阻塞锁(阻塞)

  自旋锁:轻量级锁

  阻塞锁:synchronized

参考:1. java锁分类  2. Java 可重入锁和不可重入锁的区别

四、JUC并发包中常用类(java.util.concurrent)

 1..JUC的atomic包中AtomicBoolean、AtomicInteger、AtomicReference等原子变量类。运用了CAS

     2.1 AtomicInteger、AtomicLong和AtomicBoolean

     2.2 JDK1.8:LongAdder、DoubleAdder  分段锁 效率高

 2.JUC的locks包中的AbstractQueuedSynchronizer(AQS)、ReentantLock(显式锁)、ReentrantReadWriteLock等类。

 3.JUC下的一些同步工具类(tools):CountDownLatch(闭锁)、Semaphore(信号量)、CyclicBarrier(栅栏)等。

 4.JUC下的一些并发容器类(collections):ConcurrentHashMap、CopyOnWriteArrayList等。

 5.JUC下的一些阻塞队列实现类(collections):ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue等。

 6.JUC下的一些Executor框架的相关类(executor): 线程池的工厂类->Executors 线程池的实现类->ThreadPoolExecutor/ForkJoinPool。

 五、常用锁

 1.synchronizedReentrantLock的区别

  1)用法不同:synchronized 可以用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用于代码块。

     2)获取锁和释放锁的机制不同:synchronized 是自动加锁和释放锁的,而 ReentrantLock 需要手动加锁和释放锁。

     3)锁类型不同:synchronized 是非公平锁,而 ReentrantLock 默认为非公平锁,也可以手动指定为公平锁。

     4)响应中断不同:ReentrantLock 可以响应中断,解决死锁的问题,而 synchronized 不能响应中断。

     5)底层实现不同:synchronized 是 JVM 层面通过监视器(Monitor)实现的,而 ReentrantLock 是基于 AQS 实现的。

 2.ReentrantLock、ReentrantReadWriteLock 和StampedLock的区别

特性是否支持重入是否支持锁升级适合场景
ReentrantLock 独占可重入 纯写入
ReentrantReadWriteLock 非独占可重读,读写锁,悲观锁 读写均衡
StampedLock 非独占不可重入,多模式锁,乐观锁 读多写少

 3.CountDownLatch(闭锁)、CyclicBarrier(栅栏)和Semaphore(信号量)的区别?JUC下的一些同步工具类(tools

   1)CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同:

CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后,它才执行;

  2)CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行;

另外,CountDownLatch是不能够重用的,而CyclicBarrier是可以重用的。

  3)Semaphore其实和锁有点类似,它一般用于控制对某组资源的访问权限。

 

posted @ 2022-08-23 17:39  遇见神龙  阅读(176)  评论(0编辑  收藏  举报