Java 偏向锁适用场景

林欢喜 Java经验 发布时间:2025-12-25 15:11:36 阅读数:11749 1
下文笔者讲述java偏向锁简介说明,如下所示

偏向锁核心特性

偏向锁是Jav 锁优化(偏向锁→轻量级锁→重量级锁)
       核心设计目标是消除无竞争场景下的锁获取开销,
      其关键特性如下:
       1.偏向性:
           锁会偏向于第一个获取它的线程,
            一旦线程获取锁后,后续该线程再次获取锁时,
            无需进行 CAS 操作或阻塞等待,仅需通过「线程 ID」判断即可快速获取锁;
       2.低开销:
            偏向锁的获取和释放仅涉及少量的内存操作(修改锁对象头的偏向线程 ID),
             几乎无性能损耗,
              远低于轻量级锁的 CAS 操作和重量级锁的内核态切换;
       3.无竞争前提:
            偏向锁仅在「单线程重复获取同一把锁」的场景下发挥最优性能,
            一旦出现多线程竞争,
            偏向锁会升级为轻量级锁(或直接撤销偏向锁);
       4.延迟初始化:
            JDK 1.6 及以上默认开启偏向锁,
              但会有一定延迟(默认 4 秒),
            避免程序启动初期大量线程竞争导致偏向锁频繁撤销。

二、偏向锁核心适用场景

   偏向锁的优势在于「低开销重复获取锁」,
     核心适用场景集中在单线程主导、无多线程竞争,
      且同一线程频繁重复获取同一把锁的业务场景,

场景1:单线程重复操作同一锁资源(核心适用场景)

这是偏向锁的最优适用场景,
    即只有一个线程持续获取、释放同一把锁,
    不存在任何其他线程竞争该锁。
    此时偏向锁会长期偏向该线程,
    避免了锁获取的额外开销,
    最大化提升性能。

例:
- 单线程环境下的集合操作
    (如单线程对 `Vector`、`synchronized` 修饰的自定义集合进行频繁添加、删除操作);
- 单线程执行的串行任务
    (如单线程处理文件读写、数据解析,
      其中包含多个同步方法/代码块,且均由同一线程调用);
- 单线程中的循环同步操作
    (如循环中多次调用 synchronized 方法,处理批量数据)。

例(单线程重复获取偏向锁)

public class BiasedLockSingleThreadDemo {
    // 锁对象,默认开启偏向锁
    private static final Object LOCK = new Object();
    private static int count = 0;

    public static void main(String[] args) throws InterruptedException {
        // 等待偏向锁延迟初始化完成(默认4秒,此处等待5秒确保生效)
        Thread.sleep(5000);

        // 单线程重复获取同一把锁
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            synchronized (LOCK) {
                count++; // 临界区操作,单线程执行无竞争
            }
        }
        long end = System.currentTimeMillis();

        System.out.println("执行完成,count=" + count);
        System.out.println("耗时:" + (end - start) + " 毫秒");
        // 偏向锁场景下耗时极短,远低于轻量级锁/重量级锁
    }
}

场景2:少量线程交替执行,无实际竞争(伪多线程场景)

存在多个线程,
    但线程之间是「交替执行」的,
   不存在同时竞争同一把锁的情况(即同一时间只有一个线程持有锁,
    后续线程获取锁时,前一个线程已释放锁)。
    此时偏向锁可依次偏向不同线程,避免锁升级,保持低开销。

 典型示例:
- 线程池核心线程数为 1 的场景
    (所有任务串行执行,由同一个核心线程处理,锁始终偏向该核心线程);
- 线程间通过顺序执行
   (如 `Thread.join()`)实现交替操作同一锁资源,无并发竞争;
- 定时任务
   (如 `Timer` 单线程调度,多个定时任务串行执行,同步代码块无竞争)。

场景3:高频次、短时间的同步操作(细粒度同步)

业务场景中存在大量高频次、
    执行时间极短的同步操作(如简单的变量修改、状态判断),
   且这些操作主要由单个线程完成,无多线程竞争。
   偏向锁的低开销特性可最大化减少同步操作对性能的影响。

 典型示例:
- 单线程下的计数器更新(如接口调用次数统计、数据处理条数统计,使用 synchronized 保证线程安全,无多线程竞争);
- 单线程中的缓存更新(如本地缓存的添加、查询、删除,同步代码块执行时间短,频繁重复调用);
- 工具类中的同步方法(如单线程使用的工具类,其同步方法被频繁调用,无多线程竞争)。

场景4:长期运行的单线程服务(后台守护线程)

后台守护线程长期运行,
   且在生命周期内持续获取同一把锁处理任务,
   无其他线程竞争该锁。偏向锁可长期偏向该守护线程,
    避免锁操作带来的性能损耗。

 典型示例:
- 日志输出线程
    (单线程负责日志写入文件,同步代码块保证日志顺序,无多线程竞争);
- 数据备份线程
   (后台单线程定时备份数据,同步操作保证备份过程的原子性,无并发竞争);
- 监控采集线程
  (单线程定时采集应用指标,同步代码块保护采集结果的完整性,无多线程竞争)。

三、偏向锁不适用场景(避免误用导致性能下降)

当场景中存在多线程竞争或不满足「单线程重复获取」条件时,
 偏向锁不仅无法提升性能,还会因「偏向锁撤销/升级」带来额外开销,具体不适用场景如下:

 场景1:多线程并发竞争同一锁资源(核心不适用场景)
这是偏向锁最不适用的场景,当多个线程同时竞争同一把锁时,
  偏向锁会频繁发生「偏向撤销」或「锁升级」:
- 首先,偏向锁会尝试撤销偏向(修改锁对象头的线程 ID),
    该过程需要暂停所有线程(SafePoint),带来额外开销;
- 若撤销失败或竞争持续,偏向锁会升级为轻量级锁,
    此时偏向锁的优化失去意义,反而因前期的偏向操作增加了性能损耗。

 典型示例:
- 高并发场景下的共享资源竞争
   (如秒杀系统中多个线程竞争同一商品库存锁);
- 多线程同时调用同一个 synchronized 方法处理业务
    (如多线程批量处理数据,同步方法存在并发竞争)。

 场景2:锁被多个线程交替获取,但竞争频繁
即使线程不是同时竞争锁,但多个线程交替获取锁的频率极高
    (如线程 A 释放锁后,线程 B 立即获取,随后线程 A 又再次获取),
    此时偏向锁会频繁切换偏向的线程,导致大量的偏向锁撤销操作,性能反而低于直接使用轻量级锁。

 典型示例:
- 线程池核心线程数大于 1,且任务均需要获取同一把锁;
- 多线程交替执行的高频同步任务(如两个线程交替修改同一共享变量,同步代码块竞争频繁)。

 场景3:同步代码块执行时间过长
偏向锁的优势是「低开销」,
     但如果同步代码块执行时间过长(如包含大量 IO 操作、复杂计算),
     即使是单线程执行,偏向锁的性能优化效果也不明显,
     反而可能因锁持有时间过长,导致后续线程竞争时锁升级的开销增加。

 典型示例:
- 同步代码块中包含文件读写、网络请求等耗时 IO 操作;
- 同步方法中执行复杂的算法计算(耗时数百毫秒甚至秒级)。

 场景4:大量短生命周期线程频繁创建与销毁
若系统中存在大量短生命周期线程(线程创建后快速执行任务并销毁),
      且这些线程都会获取同一把锁,此时偏向锁会频繁偏向新线程,
     导致大量的偏向锁撤销和重新偏向操作,带来额外性能损耗。

 典型示例:
- 无界线程池处理大量短期任务,任务均需要获取同一同步锁;
- 频繁创建临时线程执行同步操作,线程执行完毕后立即销毁。

 场景5:不需要同步的场景(误用偏向锁)
若业务场景本身不存在线程安全问题,无需使用 synchronized 或 Lock 锁,
    此时开启偏向锁毫无意义,反而会因锁对象头的偏向标记带来微小的额外开销。

偏向锁使用注意事项

1.  开启与关闭配置:
   - JDK 1.6 及以上默认开启偏向锁,可通过 JVM 参数调整:
     - 开启偏向锁(默认):`-XX:+UseBiasedLocking`
     - 关闭偏向锁:`-XX:-UseBiasedLocking`(适用于多线程竞争频繁的场景)
     - 关闭偏向锁延迟初始化:`-XX:BiasedLockingStartupDelay=0`
     (适用于程序启动后立即需要偏向锁优化的场景)

2.  偏向锁撤销的开销:
   偏向锁撤销是一个重量级操作(需要暂停所有线程到 SafePoint),
     因此在存在竞争的场景下,提前关闭偏向锁比让其自动升级更高效。

3.  与其他锁优化的配合:
   偏向锁是锁优化的第一阶段,当竞争出现时会自动升级为轻量级锁(CAS 自旋),
    若自旋失败则升级为重量级锁(阻塞),无需手动干预,但需根据业务场景选择是否开启偏向锁。

4.  锁对象的复用:
   对于频繁使用的锁对象,尽量复用(避免频繁创建新的锁对象),
    这样偏向锁能长期偏向同一线程,发挥最优性能;若频繁创建新锁对象,
    会导致偏向锁无法复用,失去优化效果。
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaJingYan/202512/17666478008527.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者