Java锁机制案例如何规避并发

wen java案例 22

本文目录导读:

Java锁机制案例如何规避并发

  1. synchronized关键字的正确使用
  2. ReentrantLock的灵活使用
  3. ReadWriteLock提升读性能
  4. 使用高级并发工具
  5. 避免死锁的策略
  6. 使用CAS操作避免阻塞
  7. 实际业务场景 - 订单库存扣减
  8. 关键建议:

我来分享几个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;
        }
    }
}

关键建议:

  1. 锁粒度最小化:只锁必要的代码块
  2. 避免嵌套锁:尽量减少锁嵌套,或保持固定顺序
  3. 使用超时机制:tryLock比lock更安全
  4. 优先使用并发工具:如AtomicInteger、ConcurrentHashMap等
  5. 读写分离:读多写少场景使用ReadWriteLock
  6. 及时释放锁:finally块中释放锁
  7. 避免锁内执行耗时操作:锁内代码尽量精简

这些案例涵盖了Java并发编程中常见的锁使用场景和规避并发问题的方法,希望能帮助你写出更安全高效的并发代码。

抱歉,评论功能暂时关闭!