本文目录导读:

- synchronized关键字的正确使用
- ReentrantLock的灵活使用
- ReadWriteLock提升读性能
- 使用高级并发工具
- 避免死锁的策略
- 使用CAS操作避免阻塞
- 实际业务场景 - 订单库存扣减
- 关键建议:
我来分享几个Java锁机制的案例,并说明如何规避并发问题。
synchronized关键字的正确使用
❌ 错误案例:
public class Counter {
private int count = 0;
// 没有同步,线程不安全
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
✅ 正确案例:
public class SafeCounter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) { // 使用独立的锁对象
count++;
}
}
public int getCount() {
synchronized (lock) { // 读取也需要同步
return count;
}
}
}
ReentrantLock的灵活使用
案例:带超时的锁获取
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;
public class TimeoutLockExample {
private final ReentrantLock lock = new ReentrantLock();
public boolean tryProcessWithTimeout() {
boolean acquired = false;
try {
// 尝试获取锁,最多等待1秒
acquired = lock.tryLock(1, TimeUnit.SECONDS);
if (acquired) {
// 执行临界区代码
System.out.println(Thread.currentThread().getName() + " 获取锁成功");
Thread.sleep(500); // 模拟业务处理
return true;
} else {
System.out.println(Thread.currentThread().getName() + " 获取锁超时");
return false;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
} finally {
if (acquired) {
lock.unlock(); // 确保释放锁
}
}
}
}
ReadWriteLock提升读性能
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheManager {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Map<String, Object> cache = new HashMap<>();
// 读操作 - 可以多个线程同时读
public Object get(String key) {
rwLock.readLock().lock();
try {
return cache.get(key);
} finally {
rwLock.readLock().unlock();
}
}
// 写操作 - 必须独占
public void put(String key, Object value) {
rwLock.writeLock().lock();
try {
cache.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
}
使用高级并发工具
CountDownLatch - 等待多个线程完成
import java.util.concurrent.CountDownLatch;
public class ParallelTaskExample {
public void executeParallelTasks() {
int taskCount = 5;
CountDownLatch latch = new CountDownLatch(taskCount);
for (int i = 0; i < taskCount; i++) {
new Thread(() -> {
try {
// 执行任务
System.out.println(Thread.currentThread().getName() + " 执行中");
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
latch.countDown(); // 任务完成,计数器减1
}
}).start();
}
try {
latch.await(); // 等待所有任务完成
System.out.println("所有任务完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
避免死锁的策略
❌ 可能死锁的案例:
public class DeadlockExample {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
System.out.println("获取lock1");
synchronized (lock2) {
System.out.println("获取lock2");
}
}
}
public void method2() {
synchronized (lock2) { // 锁顺序不一致!
System.out.println("获取lock2");
synchronized (lock1) {
System.out.println("获取lock1");
}
}
}
}
✅ 避免死锁的方案:
public class SafeLockExample {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
// 方案1:固定锁顺序
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
// 业务逻辑
}
}
}
public void method2() {
synchronized (lock1) { // 与method1顺序一致
synchronized (lock2) {
// 业务逻辑
}
}
}
// 方案2:使用tryLock避免死锁
private final ReentrantLock lockA = new ReentrantLock();
private final ReentrantLock lockB = new ReentrantLock();
public boolean safeTransfer() {
boolean lockAAcquired = false;
boolean lockBAcquired = false;
try {
lockAAcquired = lockA.tryLock(100, TimeUnit.MILLISECONDS);
if (lockAAcquired) {
lockBAcquired = lockB.tryLock(100, TimeUnit.MILLISECONDS);
if (lockBAcquired) {
// 两个锁都获取成功
return true;
}
}
return false; // 获取失败,不持有任何锁
} catch (InterruptedException e) {
return false;
} finally {
if (lockBAcquired) {
lockB.unlock();
}
if (lockAAcquired) {
lockA.unlock();
}
}
}
}
使用CAS操作避免阻塞
import java.util.concurrent.atomic.AtomicInteger;
public class CASExample {
private final AtomicInteger count = new AtomicInteger(0);
public void increment() {
// 无锁的CAS操作
count.incrementAndGet(); // 等价于 count++
}
public int getCount() {
return count.get();
}
}
实际业务场景 - 订单库存扣减
public class OrderService {
private final ReentrantLock orderLock = new ReentrantLock();
private int stock = 100; // 库存
private final Object stockLock = new Object();
// 方案1:使用synchronized
public synchronized boolean createOrderSync(String userId, int quantity) {
if (stock >= quantity) {
stock -= quantity;
return true;
}
return false;
}
// 方案2:使用ReentrantLock + 尝试机制
public boolean createOrderWithLock(String userId, int quantity) {
if (orderLock.tryLock()) { // 非阻塞获取锁
try {
if (stock >= quantity) {
// 模拟数据库操作
stock -= quantity;
return true;
}
return false;
} finally {
orderLock.unlock();
}
}
return false; // 获取锁失败,直接返回
}
// 方案3:细粒度锁(只锁库存操作)
public boolean createOrderOptimized(String userId, int quantity) {
// 非库存操作可以并行
// ... 校验用户信息等操作
synchronized (stockLock) {
if (stock >= quantity) {
stock -= quantity;
return true;
}
return false;
}
}
}
关键建议:
- 锁粒度最小化:只锁必要的代码块
- 避免嵌套锁:尽量减少锁嵌套,或保持固定顺序
- 使用超时机制:tryLock比lock更安全
- 优先使用并发工具:如AtomicInteger、ConcurrentHashMap等
- 读写分离:读多写少场景使用ReadWriteLock
- 及时释放锁:finally块中释放锁
- 避免锁内执行耗时操作:锁内代码尽量精简
这些案例涵盖了Java并发编程中常见的锁使用场景和规避并发问题的方法,希望能帮助你写出更安全高效的并发代码。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播