【Java并发编程】深入理解synchronized与ReentrantLock的中断机制

🔥 本文深入剖析Java并发编程中的synchronized与ReentrantLock在中断机制上的区别。通过实际案例演示和源码分析,帮你彻底理解:

  • synchronized为什么不支持中断?
  • ReentrantLock如何实现可中断锁?
  • 线程六大状态与中断机制的关系
  • 实战中如何选择合适的锁机制

📌 建议收藏,面试必备知识点!

📚博主匠心之作,强推专栏

在这里插入图片描述

Java中的synchronized与中断机制探索

大家好啊!好久未见、甚是想念~
今天想跟大家聊一个挺有意思的话题 —— Java中的响应中断问题。虽然在日常业务开发中可能用得不多,但是了解一下还是很有意思的。让我以一个同为Java开发者的身份,带大家一起探索一下这个机制。

先聊聊锁

说到中断,就不得不先聊聊我们最熟悉的synchronized。这可是JVM自带的最轻量级、性能最高的可重入锁。它的设计初衷就是让开发者能够屏蔽底层细节,拿来就能用,特别贴心!

后来呢,因为业务需求越来越复杂,就出现了很多基于AQS的工具锁。这些锁虽然在性能上可能比不上synchronized,但是提供了更多的功能特性。这也印证了那句老话:“有得必有失”,“万事皆为权衡”。

来点有意思的

给大家出个小题:
假设我们有这么一个场景 —— 在Java程序里定义了一个线程A,这个线程要执行的代码被synchronized锁保护着。如果此时在主线程中调用这个线程的中断方法,你觉得线程A会中断并抛出中断异常吗?

那如果换成ReentrantLock呢?结果会一样吗?

来看看具体的代码示例:

// 使用synchronized的情况
public class SynchronizedExample {
    private static final Object lock = new Object();
    
    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(() -> {
            try {
                synchronized (lock) {
                    // 模拟长时间运行
                    Thread.sleep(10000);
                }
            } catch (InterruptedException e) {
                System.out.println("synchronized中的线程被中断了!");  // 这句话不会打印
            }
        });
        
        threadA.start();
        Thread.sleep(100);  // 确保线程A已经获得了锁
        
        threadA.interrupt();  // 尝试中断线程
        System.out.println("尝试中断synchronized中的线程");
    }
}

// 使用ReentrantLock的情况
public class ReentrantLockExample {
    private static final ReentrantLock lock = new ReentrantLock();
    
    public static void main(String[] args) throws InterruptedException {
        Thread threadA = new Thread(() -> {
            try {
                lock.lockInterruptibly();  // 可中断的加锁
                try {
                    // 模拟长时间运行
                    Thread.sleep(10000);
                } finally {
                    lock.unlock();
                }
            } catch (InterruptedException e) {
                System.out.println("ReentrantLock中的线程被中断了!");  // 这句话会打印
            }
        });
        
        threadA.start();
        Thread.sleep(100);  // 确保线程A已经获得了锁
        
        threadA.interrupt();  // 尝试中断线程
        System.out.println("尝试中断ReentrantLock中的线程");
    }
}

哈哈,看到这两个问题,相信大家也猜到了 —— 肯定一个会中断,一个不会。实际情况是:

  • 使用synchronized的情况下不会中断
  • 使用ReentrantLock会中断

为什么会这样?

这就要说到Java中线程的六种状态了:

  1. 新建(NEW)

    • 线程被创建,但还没有调用start()方法
  2. 可运行(RUNNABLE)

    • 包含了操作系统中的"运行中"和"就绪"两种状态
    • 线程可能正在运行,也可能正在等待CPU时间片
  3. 阻塞(BLOCKED)

    • 线程正在等待获取监视器锁(monitor lock)
    • 这种状态特指在synchronized同步块或方法时等待锁的情况
    • 这种状态下的线程是不响应中断的
  4. 等待(WAITING)

    • 线程进入无限期等待状态
    • 调用如下方法会进入这种状态:
      • Object.wait()
      • Thread.join()
      • LockSupport.park()
    • 需要其他线程显式唤醒
  5. 超时等待(TIMED_WAITING)

    • 线程进入有限期等待状态
    • 调用如下方法会进入这种状态:
      • Thread.sleep(timeout)
      • Object.wait(timeout)
      • Thread.join(timeout)
      • LockSupport.parkNanos(timeout)
      • LockSupport.parkUntil(timeout)
    • 在指定时间后会自动唤醒
  6. 终止(TERMINATED)

    • 线程执行完毕或因异常退出了run()方法
    • 线程结束后的最终状态

使用synchronized时,线程会进入BLOCKED(阻塞)状态,这是一种不响应中断的状态。即使你调用了中断方法,线程也不会被唤醒。
ReentrantLock是基于AQS实现的,等待锁的线程会进入一个阻塞队列,此时线程处于可响应中断的状态(注意,不是BLOCKED状态)。当我们调用线程的interrupt()方法时,应用程序会调用操作系统的中断接口,触发线程苏醒。操作系统会返回一个标志,告诉应用程序线程已经苏醒,然后应用程序就会抛出中断异常,这样就能被我们的业务代码捕获到啦!
再往下就是进行业务的相关处理。

为什么synchronized最初要这么设计?

这其实是有原因的:

  1. 设计理念简单明确:

    • 简单易用
    • 性能优先
    • 不需要开发者操心太多细节
  2. 性能至上:

    • 是JVM原生支持的,经过了大量优化(偏向锁、轻量级锁、自旋锁)
    • 如果加入中断处理,势必会带来额外开销
    • 而且大多数场景下,我们确实也用不到中断锁等待这个功能
  3. 后来为什么要有ReentrantLock?
    随着并发编程的发展,开发者发现synchronized有些局限性:

    • 不支持尝试加锁(try-lock)
    • 不支持超时机制
    • 不支持中断
    • 不支持读写分离

所以在JDK 5中,Java引入了java.util.concurrent.locks包,其中最重要的就是ReentrantLock,专门用来解决这些问题。

怎么样,现在对Java中的中断机制理解得更清楚了吗?😊

写在最后

🎉 通过本文的学习,相信大家对Java中的synchronized与中断机制有了更深入的理解。特别是理解了为什么synchronized和ReentrantLock在处理中断时会有不同的表现,这对我们在实际开发中选择合适的锁机制很有帮助!

📚博主匠心之作,强推专栏

💌 与博主互动 & 技术支持

👋 读到这里,不妨留下你的想法和问题,博主会第一时间回复!

遇到技术难题?

  • 在项目中遇到线程中断相关的问题?
  • 需要并发编程的最佳实践建议?
  • 作业&实验需要帮助?

🤝 专业服务

① 🛠️ 技术咨询与问题解答:Java/Python/前后端/数据库/算法等各领域问题

② 🚀 项目开发与合作

  • 前端开发:Web应用、响应式设计、交互体验优化
  • 后端开发:Java/Python/Node.js微服务、API设计
  • 移动应用:H5、小程序、公众号开发
  • 全栈解决方案:从需求分析到部署维护

③ 📝 代码审查与优化:性能调优、架构改进、最佳实践建议

④ 📚 学习指导与作业辅导:为在校学生提供编程作业指导和学习路径规划

🔍 如有合作需求,欢迎私信联系,期待与您共创价值!


🎯 我是果冻~,一个热爱技术、乐于分享的开发者
📚 更多精彩内容,欢迎关注我的博客,与我交流!
🌟 如果本文对你有帮助,别忘了点赞👍收藏⭐评论💬一键三连支持博主!

期待与你在评论区相遇,共同进步!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值