首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 可见性、原子性和有序性问题:并发编程Bug的源头
02 | Java内存模型:看Java如何解决可见性和有序性问题
03 | 互斥锁(上):解决原子性问题
04 | 互斥锁(下):如何用一把锁保护多个资源?
05 | 一不小心就死锁了,怎么办?
06 | 用“等待-通知”机制优化循环等待
07 | 安全性、活跃性以及性能问题
08 | 管程:并发编程的万能钥匙
09 | Java线程(上):Java线程的生命周期
10 | Java线程(中):创建多少线程才是合适的?
11 | Java线程(下):为什么局部变量是线程安全的?
12 | 如何用面向对象思想写好并发程序?
13 | 理论基础模块热点问题答疑
14 | Lock和Condition(上):隐藏在并发包中的管程
15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?
16 | Semaphore:如何快速实现一个限流器?
17 | ReadWriteLock:如何快速实现一个完备的缓存?
18 | StampedLock:有没有比读写锁更快的锁?
19 | CountDownLatch和CyclicBarrier:如何让多线程步调一致?
20 | 并发容器:都有哪些“坑”需要我们填?
21 | 原子类:无锁工具类的典范
22 | Executor与线程池:如何创建正确的线程池?
23 | Future:如何用多线程实现最优的“烧水泡茶”程序?
24 | CompletableFuture:异步编程没那么难
25 | CompletionService:如何批量执行异步任务?
26 | Fork/Join:单机版的MapReduce
27 | 并发工具类模块热点问题答疑
28 | Immutability模式:如何利用不变性解决并发问题?
29 | Copy-on-Write模式:不是延时策略的COW
30 | 线程本地存储模式:没有共享,就没有伤害
31 | Guarded Suspension模式:等待唤醒机制的规范实现
32 | Balking模式:再谈线程安全的单例模式
33 | Thread-Per-Message模式:最简单实用的分工方法
34 | Worker Thread模式:如何避免重复创建线程?
35 | 两阶段终止模式:如何优雅地终止线程?
36 | 生产者-消费者模式:用流水线思想提高效率
37 | 设计模式模块热点问题答疑
38 | 案例分析(一):高性能限流器Guava RateLimiter
39 | 案例分析(二):高性能网络应用框架Netty
40 | 案例分析(三):高性能队列Disruptor
41 | 案例分析(四):高性能数据库连接池HiKariCP
42 | Actor模型:面向对象原生的并发模型
43 | 软件事务内存:借鉴数据库的并发经验
44 | 协程:更轻量级的线程
45 | CSP模型:Golang的主力队员
当前位置:
首页>>
技术小册>>
Java并发编程实战
小册名称:Java并发编程实战
### 03 | 互斥锁(上):解决原子性问题 在Java并发编程的广阔领域中,原子性问题是一个核心概念,它直接关系到程序的正确性和性能。当多个线程同时访问共享资源时,如果没有适当的同步机制,就可能导致数据竞争、脏读、不可重复读或幻读等并发问题。本章将深入探讨互斥锁(Mutex)作为解决原子性问题的一种重要手段,首先聚焦于互斥锁的基本原理、实现方式及其在Java中的具体应用。 #### 一、原子性问题概述 **原子性**是指一个操作或动作在执行过程中,要么全部完成,要么完全不执行,不会被其他线程的操作打断。在并发环境下,保证操作的原子性至关重要,因为一旦操作被分割成多个步骤,并且这些步骤在不同的线程间交错执行,就可能引发数据不一致的问题。 #### 二、互斥锁的基本原理 互斥锁(Mutual Exclusion Lock)是同步机制的一种,用于保证在任何时刻,只有一个线程能够访问特定的代码区域或资源。当一个线程获取了互斥锁后,其他尝试进入该区域的线程将被阻塞,直到锁被释放。这种机制有效地防止了多个线程同时修改同一数据而导致的冲突。 互斥锁的基本特性包括: 1. **互斥性**:确保同一时间只有一个线程可以访问被保护的资源。 2. **无死锁**:系统不会进入一种状态,其中线程相互等待对方释放锁,从而导致所有线程都无法继续执行。 3. **公平性**(可选):可选地,互斥锁可以提供一种机制,确保线程按照请求锁的顺序获得锁。 #### 三、Java中的互斥锁实现 在Java中,互斥锁的实现主要通过`java.util.concurrent.locks`包下的`Lock`接口及其实现类,如`ReentrantLock`来完成。与传统的`synchronized`关键字相比,`Lock`接口提供了更灵活的锁操作,如尝试非阻塞地获取锁、可中断地获取锁以及尝试获取锁一段时间后自动放弃等。 ##### 3.1 ReentrantLock的使用 `ReentrantLock`是一个可重入的互斥锁,它支持一个与之关联的`Condition`对象,用于实现线程间的通信。以下是一个使用`ReentrantLock`的基本示例: ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Counter { private final Lock lock = new ReentrantLock(); private int count = 0; public void increment() { lock.lock(); // 获取锁 try { count++; // 临界区,保证原子性 } finally { lock.unlock(); // 释放锁 } } public int getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } } ``` 在这个例子中,`increment`和`getCount`方法都通过`ReentrantLock`来确保对共享变量`count`的访问是互斥的,从而保证了操作的原子性。 ##### 3.2 锁的公平性 `ReentrantLock`支持公平锁和非公平锁两种模式。默认情况下,`ReentrantLock`采用非公平锁模式,即线程在尝试获取锁时,不会按照请求锁的顺序来排队,这通常能提供更好的性能。但在某些场景下,如果希望按照请求的顺序来分配锁,可以创建`ReentrantLock`实例时传入`true`作为参数来启用公平锁模式: ```java Lock lock = new ReentrantLock(true); // 创建一个公平锁 ``` #### 四、互斥锁的高级特性 ##### 4.1 尝试非阻塞地获取锁 `ReentrantLock`提供了`tryLock()`方法,该方法尝试获取锁,如果锁当前未被其他线程持有,则立即返回`true`,并将锁的持有权赋予当前线程;如果锁已被其他线程持有,则不会使当前线程阻塞,而是立即返回`false`。 ##### 4.2 可中断地获取锁 `ReentrantLock`还支持可中断的锁获取操作,即线程在等待锁的过程中,可以被其他线程中断。这通过`lockInterruptibly()`方法实现,如果在等待锁的过程中线程被中断,则线程会抛出`InterruptedException`。 ##### 4.3 尝试获取锁一段时间后自动放弃 `ReentrantLock`还提供了`tryLock(long time, TimeUnit unit)`方法,允许线程尝试在指定时间内获取锁,如果在这段时间内成功获取锁,则返回`true`;如果在超时时间到达时仍未获取到锁,则返回`false`。 #### 五、互斥锁与性能 虽然互斥锁在解决原子性问题上非常有效,但它也可能成为性能瓶颈。因为当线程获取不到锁时,会被阻塞或进行忙等待,这会增加线程切换的成本和CPU的消耗。因此,在使用互斥锁时,需要注意以下几点: 1. **最小化锁的持有时间**:尽快完成临界区的操作,然后释放锁,以减少线程等待锁的时间。 2. **减少锁的粒度**:尽量只对需要同步的资源加锁,避免对大量数据进行整体加锁。 3. **考虑使用读写锁**:对于读多写少的场景,可以考虑使用`ReentrantReadWriteLock`,它允许多个线程同时读取数据,但写操作仍然是互斥的。 #### 六、总结 互斥锁是解决Java并发编程中原子性问题的重要工具。通过`ReentrantLock`等实现类,Java提供了灵活且强大的锁机制,帮助开发者有效地管理对共享资源的访问。然而,锁的使用也需要谨慎,不当的锁策略可能导致性能问题或死锁。因此,在实际开发中,应根据具体场景和需求,选择合适的锁策略,并关注锁的性能影响和安全性。 通过本章的学习,希望读者能够理解互斥锁的基本原理,掌握在Java中使用互斥锁解决原子性问题的技巧,并能够在实际项目中灵活运用这些知识,提高并发程序的稳定性和性能。
上一篇:
02 | Java内存模型:看Java如何解决可见性和有序性问题
下一篇:
04 | 互斥锁(下):如何用一把锁保护多个资源?
该分类下的相关小册推荐:
Mybatis合辑3-Mybatis动态SQL
Java必知必会-Maven高级
Java语言基础5-面向对象初级
手把手带你学习SpringBoot-零基础到实战
Java语言基础12-网络编程
Java语言基础8-Java多线程
Java性能调优实战
Java语言基础15-单元测试和日志技术
Java语言基础1-基础知识
Java语言基础16-JDK8 新特性
SpringBoot合辑-初级篇
Java语言基础6-面向对象高级