java并发编程线程锁机制(锁的四种状态|无锁状态|偏向锁|轻量级锁|重量级锁|锁竞争|锁升级)(代码片段)

韩曙亮 韩曙亮     2023-01-02     293

关键词:





一、悲观锁示例 ( ReentrantLock )



ReentrantLocksynchronized 都是悲观锁 ;

ReentrantLockLock 接口的实现类 ,

public class ReentrantLock implements Lock, java.io.Serializable 

Lock 是一种锁的机制 , 调用 lock() 方法 , 表示要对下方的代码进行加锁 , 这些代码是线程安全的 ;

代码执行完毕后 , 调用 unlock() 释放锁 ;

lock()unlock() 之间的内容 , 就是同步代码块内容 ;

public interface Lock 

    void lock();

    void lockInterruptibly() throws InterruptedException;

    boolean tryLock();

    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    void unlock();

    Condition newCondition();

悲观锁都是重量级锁 ;





二、重量级锁弊端



JDK 1.2 1.2 1.2 之间 , 只有一个 synchronized 重量级锁 ;

Java 虚拟机创建了线程 A , B 两个线程 , JVM 将线程托管给操作系统进行调度执行 , 线程同步依靠 synchronized 重量级锁实现 , 线程 A , B 之间会进行竞争 , 哪个抢到 synchronized 锁 , 哪个线程就可以执行 ;

使用 synchronized 使用起来效率很低 , 假如在 synchronized 同步代码块中 , 只有一行代码 , 执行 1 1 1 ms , 但是系统调度线程 , 可能需要 20 20 20 ms 才能轮到线程执行 , 线程执行的时间远远小于调度时间 , 这样线程执行效率很低 ;

为了 Java 程序的提升执行效率 , Java 引入了 4 4 4 种锁状态 , 无锁 , 偏向锁 , 轻量级锁 , 重量级锁 ;





三、锁的四种状态 ( 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 )



Java 虚拟机堆内存中的对象数据中 , 每个对象都有一个对象头 , 结构如下 :

对象头 中封装了 锁的状态 , 当锁的状态发生改变时 , 对应的锁的标志位也进行相应修改 ;


无锁状态 : 不进行加锁 , 线程不安全 ;

偏向锁 : 1 1 1 个访问 共享资源 的线程 A , 做一个标记 , 不加锁 , 这个标记称为 " 偏向锁 " ; 偏向锁 偏向第一个访问的线程 ; 如果没有新的线程竞争该锁 , 则该 偏向锁一直被该线程持有 , 不会释放锁 ; 如果出现多个线程同时访问 , 持有偏向锁的线程会 释放该偏向锁 , 并添加轻量级锁 ;

  • 锁竞争 : 多个线程尝试获取同一个锁 ;
    • 没有竞争 : 如果每次获取都很顺利 , 没有出现阻塞 , 则没有竞争 ;
    • 有竞争 : 如果线程尝试获取锁 , 但是锁被其它线程持有 , 那么 该线程需要等待 , 期间 阻塞或自旋 , 只要是等待就会产生消耗 , 这就产生了锁竞争 , 并且 有一定的性能消耗 ;
  • 锁竞争消耗 : 多数情况下锁会被多个线程获取多次 , 多个线程竞争一个锁 , 这样就存在竞争 , 竞争期间 阻塞或自旋 , 锁获取的代价很大 ;
  • 偏向锁优点 : 降低了线程获取锁的代价 , 偏向锁不存在锁竞争问题 ;
  • 偏向锁意义 : 偏向锁并 不是真正意义上的锁 , 只是给单线程执行加了层保险 , 如果没有线程竞争该锁 , 则正常执行 , 如果有线程竞争 , 则将偏向锁升级为轻量级锁 ;

轻量级锁 : 自旋锁 , 等待期间一直做自旋操作 , 效率较高 , 但是空耗 CPU 性能 ; 自旋就是 while / for 循环 ;

重量级锁 : 系统提供的 synchronized , ReentrantLock 等重量级锁 , 由操作系统进行调度 , 可进行阻塞 ;





四、锁的四种状态之间的转换 ( 无锁状态 -> 偏向锁 -> 轻量级锁 -> 重量级锁 )



锁的四种状态之间转换 : 在保证线程安全的前提下 , 尽可能提升效率 ;

  • 无锁 : 刚开始执行时 , 无锁 ;

  • 无锁 -> 偏向锁 : 1 1 1 个线程访问共享资源时 , 无锁状态升级为偏向锁 ;

  • 偏向锁 -> 轻量级锁 : 2 2 2 个线程再来访问 共享资源 时 , 偏向锁 升级为 轻量级锁 ;

  • 轻量级锁 -> 重量级锁 : 如果 自旋线程数 超过 CPU 核数一半 , 或 单个线程超过 10 10 10 次自旋 , 自动将锁升级为重量级锁 ;

java并发专题之三java线程同步

  从JDK5引入CAS原子操作,但没有对synchronized关键字做优化,而是增加了J.U.C.concurrent,concurrent包有更好的性能;从JDK6对synchronized的实现机制进行了较大调整,包括使用JDK5引进的CAS自旋之外,还增加了自适应的CAS自旋、锁消除... 查看详情

并发编程的灵魂:cas机制详解(代码片段)

...制存在的一些问题以及在Java中怎么使用CAS机制。其实Java并发框架的基石一共有两块,一块是本文介绍的CAS,另一块就是AQS,后续也会写文章介绍。什么是CAS机制CAS机制是一种数据更新的方式。在具体讲什么是CAS机制之前,我们... 查看详情

并发编程——synchronized优化原理

如果有兴趣了解更多相关内容,欢迎来我的个人网站看看:耶瞳空间一:基本概念使用synchronized实现线程同步,即加锁,实现的是悲观锁。加锁可以使一段代码在同一时间只有一个线程可以访问,在增加安... 查看详情

linuxc++多线程同步的四种方式

...;但不同线程之间的指令很难说清楚是哪一个先执行,在并发情况下,指令执行的先后顺序由内核决定。如果运行的结果依赖于不同线程执行的先后的话,那么就会形成竞争条件,在这样的情况下,计算的结果很难预知,所以应... 查看详情

并发编程:等待/通知机制

wait&notify/notifyAll通过之前的文章,https://www.cnblogs.com/fcb-it/p/13282740.html我们已经知道了重量级锁会存在等待队列和阻塞队列,这两个队列是做什么用的呢?阻塞队列:BLOCKED状态的线程会在该队列,当发现锁可用时,线程有机会... 查看详情

java并发编程:管程内存模型无锁并发线程池aqs原理与锁线程安全集合类并发设计模式

文章目录基础1.进程与线程2.并发与并行3.同步与异步4.主线程与守护线程5.Thread与Runnable6.线程方法7.线程状态管程1.共享问题、临界区、竞态条件2.Monitor3.synchronized4.wait&notify5.Park&Unpark6.活跃性7.ReentrantLock8.lockvssynchronized内存... 查看详情

java并发编程——深入理解自旋锁

1.什么是自旋锁自旋锁(spinlock):是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态... 查看详情

多线程高并发之synchronized锁及其膨胀

参考技术A在并发编程中,synchronized锁因其使用简单,在线程间同步被广泛应用。下面对其原理及锁升级过程进行探究。当实例方法被synchronized修饰时,通过当前实例调用此方法的所有线程共用一把锁,不同对象调用此方法线程... 查看详情

面试java基础锁

...态只能升级不能降级。无锁没有锁对资源进行锁定,所有线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。其他修改失败的线程会不断重试,直到修改成功,如CAS原理和应用是无锁的实现。偏向锁偏向锁是指一... 查看详情

java并发编程:管程内存模型无锁并发线程池aqs原理与锁线程安全集合类并发设计模式(代码片段)

文章目录基础1.进程与线程2.并发与并行3.同步与异步4.主线程与守护线程5.Thread与Runnable6.线程方法7.线程状态管程1.共享问题、临界区、竞态条件2.Monitor3.synchronized4.wait&notify5.Park&Unpark6.活跃性7.ReentrantLock8.lockvssynchronized内存... 查看详情

java并发编程:使用synchronized获取互斥锁的几点说明

在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确... 查看详情

java并发编程:管程内存模型无锁并发线程池aqs原理与锁线程安全集合类并发设计模式(代码片段)

文章目录基础1.进程与线程2.并发与并行3.同步与异步4.主线程与守护线程5.Thread与Runnable6.线程方法7.线程状态管程1.共享问题、临界区、竞态条件2.Monitor3.synchronized4.wait&notify5.Park&Unpark6.活跃性7.ReentrantLock8.lockvssynchronized内存... 查看详情

java并发编程常见锁类型

锁是java并发编程中最重要的同步机制。锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消息。锁是解决并发冲突的重要工具。在开发中我们会用到很多类型的锁,每种锁都有其自身的特点和适用... 查看详情

java并发编程11.原子变量与非阻塞同步机制

在非阻塞算法中不存在死锁和其他活跃性问题。在基于锁的算法中,如果一个线程在休眠或自旋的同时持有一个锁,那么其他线程都无法执行下去,而非阻塞算法不会受到单个线程失败的影响。锁的劣势许多JVM都对非竞争锁获取... 查看详情

多线程之锁机制(代码片段)

前言  在Java并发编程实战,会经常遇到多个线程访问同一个资源的情况,这个时候就需要维护数据的一致性,否则会出现各种数据错误,其中一种同步方式就是利用Synchronized关键字执行锁机制,锁机制是先给共享资源上锁,... 查看详情

java并发编程:守护线程与线程阻塞的四种情况

守护线程Java中有两类线程:UserThread(用户线程)、DaemonThread(守护线程)用户线程即运行在前台的线程,而守护线程是运行在后台的线程。守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通、非守护线程仍然运行时... 查看详情

图解java线程状态转换(代码片段)

大家好,我是阿星,好久不见,欢迎来到Java并发编程系列番外篇线程状态转换,内容通俗易懂,请放心食用。线程状态先来个开场四连问Java线程状态有几个?Java线程状态是如何转换?Java线程状态转换... 查看详情

java并发编程面试题

   并发编程面试题-内存模型说下内存模型定义为什么要有内存模型为什么要重排序,重排序在什么时候排如何约束重排序规则happens-before什么是顺序一致性CAS实现的原理,是阻塞还是非阻塞方式?什么时候用,使用时... 查看详情