本文目录导读:

在Java中实现同步锁机制主要有以下几种方式,我会从简单到复杂逐一说明,并提供实际案例。
synchronized 关键字
方法级别的同步
public class Counter {
private int count = 0;
// 同步实例方法
public synchronized void increment() {
count++;
}
// 同步静态方法(锁住整个类)
public static synchronized void staticMethod() {
// 静态方法同步
}
}
代码块级别的同步
public class BankAccount {
private double balance = 0;
private final Object lock = new Object(); // 专门的锁对象
public void deposit(double amount) {
synchronized (lock) {
balance += amount;
System.out.println("存款后余额: " + balance);
}
}
public void withdraw(double amount) {
synchronized (lock) {
if (balance >= amount) {
balance -= amount;
System.out.println("取款后余额: " + balance);
}
}
}
}
实际案例:线程安全的计数器
public class ThreadSafeCounter {
private int count = 0;
public void increment() {
synchronized (this) {
count++;
System.out.println(Thread.currentThread().getName() + " 计数: " + count);
}
}
public static void main(String[] args) {
ThreadSafeCounter counter = new ThreadSafeCounter();
// 创建10个线程同时计数
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 100; j++) {
counter.increment();
}
}, "线程-" + i).start();
}
}
}
Lock 接口及其实现
使用 ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final Lock lock = new ReentrantLock();
private int sharedResource = 0;
public void accessResource() {
lock.lock(); // 获取锁
try {
sharedResource++;
System.out.println(Thread.currentThread().getName() + " 访问资源: " + sharedResource);
} finally {
lock.unlock(); // 确保释放锁
}
}
// 可中断的锁获取
public void interruptibleAccess() throws InterruptedException {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
System.out.println("获取锁成功,执行操作");
} finally {
lock.unlock();
}
} else {
System.out.println("获取锁超时");
}
}
}
读写锁案例
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockExample {
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock readLock = rwLock.readLock();
private final Lock writeLock = rwLock.writeLock();
private Map<String, String> cache = new HashMap<>();
public String get(String key) {
readLock.lock(); // 读锁,可多个线程同时读
try {
return cache.get(key);
} finally {
readLock.unlock();
}
}
public void put(String key, String value) {
writeLock.lock(); // 写锁,独占
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
}
}
高级同步工具
CountDownLatch(倒计时闩锁)
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3);
// 创建3个工作线程
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 完成任务");
latch.countDown(); // 计数器减1
}, "工作线程-" + i).start();
}
latch.await(); // 等待所有线程完成
System.out.println("所有任务完成,继续执行主线程");
}
}
Semaphore(信号量)
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private final Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问
public void accessResource() {
try {
semaphore.acquire(); // 获取许可
System.out.println(Thread.currentThread().getName() + " 访问资源");
Thread.sleep(1000); // 模拟资源访问
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
semaphore.release(); // 释放许可
}
}
}
最佳实践建议
选择合适的同步方式
public class SynchronizationBestPractice {
// 1. 简单的同步使用 synchronized
private int simpleCounter = 0;
public synchronized void increment() {
simpleCounter++;
}
// 2. 需要高级功能时使用 Lock
private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
public void complexOperation() {
lock.lock();
try {
// 需要超时、可中断等高级功能
} finally {
lock.unlock();
}
}
// 3. 读多写少场景使用读写锁
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 4. 避免死锁:按固定顺序获取锁
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void avoidDeadlock() {
synchronized (lock1) {
synchronized (lock2) {
// 始终先获取 lock1,再获取 lock2
}
}
}
}
注意事项
- 粒度控制:同步块的范围要尽可能小,只保护必要的共享资源
- 避免死锁:多个锁时要保持一致的获取顺序
- 使用finally释放锁:Lock接口必须在finally块中释放锁
- 性能考虑:
synchronized适合简单场景ReentrantLock提供更灵活的锁机制ReadWriteLock适合读多写少场景
选择哪种同步机制取决于具体的业务需求、性能要求和代码复杂度,简单的计数器使用 synchronized,复杂的高并发场景考虑 Lock 接口和并发工具类。