Java 并发编程深度解析:从 synchronized 到 Lock 的演进与实践
引言
Java 并发编程一直是后端开发中的核心技术领域,随着多核处理器的普及和高并发应用的需求增长,掌握并发编程的核心原理和最佳实践变得尤为重要。本文将深入解析 Java 并发编程中的关键技术点,从传统的 synchronized 关键字到现代的 Lock 接口,通过具体的代码实例和原理分析,帮助开发者理解并发编程的本质和演进过程。
synchronized 关键字:Java 并发的基石
基本原理与实现
synchronized 是 Java 提供的内置锁机制,基于对象监视器(Monitor)实现。每个 Java 对象都有一个内置的监视器锁,当线程进入 synchronized 代码块时,会自动获取该锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | public class SynchronizedExample {     private int counter = 0;     private final Object lock = new Object();               public synchronized void incrementMethod() {         counter++;     }               public void incrementBlock() {         synchronized (lock) {             counter++;         }     }               public static synchronized void staticMethod() {                  System.out.println("静态同步方法");     } }
  | 
 
synchronized 的底层实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   |  public void synchronizedMethod() {     synchronized (this) {                           counter++;              } }
 
  public class MonitorImplementation {     
 
 
 
 
 
           private volatile Thread owner;             private volatile int recursions;           private Queue<Thread> entryList;           private Set<Thread> waitSet;           }
 
  | 
 
synchronized 的优化演进
JDK 1.6 引入了锁优化技术,包括偏向锁、轻量级锁和重量级锁:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   | public class LockOptimization {     private int value = 0;          public void demonstrateLockEscalation() {                  synchronized (this) {             value++;          }                           new Thread(() -> {             synchronized (this) {                 value++;              }         }).start();                           for (int i = 0; i < 10; i++) {             new Thread(() -> {                 synchronized (this) {                     try {                         Thread.sleep(100);                          value++;                     } catch (InterruptedException e) {                         Thread.currentThread().interrupt();                     }                 }             }).start();         }     } }
  | 
 
Lock 接口:更灵活的并发控制
ReentrantLock 的核心特性
ReentrantLock 提供了比 synchronized 更丰富的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
   | import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.Condition; import java.util.concurrent.TimeUnit;
  public class ReentrantLockExample {     private final ReentrantLock lock = new ReentrantLock();     private final Condition condition = lock.newCondition();     private int counter = 0;     private boolean ready = false;               public void interruptibleLock() throws InterruptedException {         lock.lockInterruptibly();          try {                          counter++;         } finally {             lock.unlock();         }     }               public boolean tryLockExample() {         if (lock.tryLock()) {             try {                 counter++;                 return true;             } finally {                 lock.unlock();             }         }         return false;      }               public boolean timeoutLock() throws InterruptedException {         if (lock.tryLock(5, TimeUnit.SECONDS)) {             try {                 counter++;                 return true;             } finally {                 lock.unlock();             }         }         return false;      }               public void producer() throws InterruptedException {         lock.lock();         try {                          counter++;             ready = true;             condition.signalAll();          } finally {             lock.unlock();         }     }          public void consumer() throws InterruptedException {         lock.lock();         try {             while (!ready) {                 condition.await();              }                          System.out.println("消费数据: " + counter);         } finally {             lock.unlock();         }     } }
   | 
 
AQS(AbstractQueuedSynchronizer)原理解析
ReentrantLock 基于 AQS 实现,AQS 是 Java 并发包的核心基础类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
   |  public abstract class AbstractQueuedSynchronizer {          private volatile int state;               private transient volatile Node head;               private transient volatile Node tail;               static final class Node {         volatile Thread thread;              volatile Node prev;                  volatile Node next;                  volatile int waitStatus;         }               protected boolean tryAcquire(int arg) {         throw new UnsupportedOperationException();     }               protected boolean tryRelease(int arg) {         throw new UnsupportedOperationException();     } }
 
  public class ReentrantLock implements Lock {     private final Sync sync;          abstract static class Sync extends AbstractQueuedSynchronizer {                  final boolean nonfairTryAcquire(int acquires) {             final Thread current = Thread.currentThread();             int c = getState();             if (c == 0) {                                  if (compareAndSetState(0, acquires)) {                     setExclusiveOwnerThread(current);                     return true;                 }             } else if (current == getExclusiveOwnerThread()) {                                  int nextc = c + acquires;                 if (nextc < 0)                      throw new Error("Maximum lock count exceeded");                 setState(nextc);                 return true;             }             return false;         }     } }
 
  | 
 
读写锁:优化读多写少场景
ReentrantReadWriteLock 的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
   | import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.HashMap; import java.util.Map;
  public class ReadWriteLockExample {     private final Map<String, String> cache = new HashMap<>();     private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();     private final ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();     private final ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();               public String get(String key) {         readLock.lock();         try {             System.out.println(Thread.currentThread().getName() + " 正在读取");             Thread.sleep(100);              return cache.get(key);         } catch (InterruptedException e) {             Thread.currentThread().interrupt();             return null;         } finally {             readLock.unlock();         }     }               public void put(String key, String value) {         writeLock.lock();         try {             System.out.println(Thread.currentThread().getName() + " 正在写入");             Thread.sleep(200);              cache.put(key, value);         } catch (InterruptedException e) {             Thread.currentThread().interrupt();         } finally {             writeLock.unlock();         }     }               public void lockDowngrade(String key, String value) {         writeLock.lock();         try {                          cache.put(key, value);                                       readLock.lock();         } finally {             writeLock.unlock();          }                  try {                          String result = cache.get(key);             System.out.println("读取结果: " + result);         } finally {             readLock.unlock();          }     } }
   | 
 
性能对比与选择指南
基准测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
   | import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.CountDownLatch;
  public class LockPerformanceTest {     private static final int THREAD_COUNT = 10;     private static final int ITERATIONS = 1000000;          private int synchronizedCounter = 0;     private int lockCounter = 0;     private final Object syncLock = new Object();     private final ReentrantLock reentrantLock = new ReentrantLock();               public void testSynchronized() throws InterruptedException {         CountDownLatch latch = new CountDownLatch(THREAD_COUNT);         long startTime = System.currentTimeMillis();                  for (int i = 0; i < THREAD_COUNT; i++) {             new Thread(() -> {                 for (int j = 0; j < ITERATIONS; j++) {                     synchronized (syncLock) {                         synchronizedCounter++;                     }                 }                 latch.countDown();             }).start();         }                  latch.await();         long endTime = System.currentTimeMillis();         System.out.println("synchronized 耗时: " + (endTime - startTime) + "ms");         System.out.println("synchronized 结果: " + synchronizedCounter);     }               public void testReentrantLock() throws InterruptedException {         CountDownLatch latch = new CountDownLatch(THREAD_COUNT);         long startTime = System.currentTimeMillis();                  for (int i = 0; i < THREAD_COUNT; i++) {             new Thread(() -> {                 for (int j = 0; j < ITERATIONS; j++) {                     reentrantLock.lock();                     try {                         lockCounter++;                     } finally {                         reentrantLock.unlock();                     }                 }                 latch.countDown();             }).start();         }                  latch.await();         long endTime = System.currentTimeMillis();         System.out.println("ReentrantLock 耗时: " + (endTime - startTime) + "ms");         System.out.println("ReentrantLock 结果: " + lockCounter);     } }
   | 
 
选择指南
| 场景 | 
推荐方案 | 
理由 | 
| 简单的互斥访问 | 
synchronized | 
语法简洁,JVM优化充分 | 
| 需要超时或中断 | 
ReentrantLock | 
提供更灵活的控制 | 
| 读多写少场景 | 
ReadWriteLock | 
读操作并发性能更好 | 
| 公平性要求 | 
ReentrantLock(fair) | 
支持公平锁模式 | 
| 条件变量需求 | 
ReentrantLock + Condition | 
比 wait/notify 更灵活 | 
最佳实践与注意事项
1. 锁的正确使用模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   | public class LockBestPractices {     private final ReentrantLock lock = new ReentrantLock();               public void correctLockUsage() {         lock.lock();         try {                      } finally {             lock.unlock();          }     }               public void incorrectLockUsage() {         lock.lock();                  lock.unlock();      }               private static final Object lock1 = new Object();     private static final Object lock2 = new Object();          public void avoidDeadlock() {                  synchronized (lock1) {             synchronized (lock2) {                              }         }     } }
  | 
 
2. 性能优化建议
- 减少锁的粒度:使用更细粒度的锁来减少竞争
 
- 避免锁嵌套:减少死锁风险和性能开销
 
- 合理选择锁类型:根据具体场景选择最适合的锁机制
 
- 使用无锁数据结构:在可能的情况下使用 ConcurrentHashMap 等无锁容器
 
总结
Java 并发编程从 synchronized 到 Lock 的演进体现了对性能和灵活性的不断追求。synchronized 作为 Java 的内置锁机制,经过多年优化已经具备了很好的性能表现,适合大多数简单的同步场景。而 Lock 接口及其实现类则提供了更丰富的功能和更细粒度的控制,适合复杂的并发场景。
理解这些并发机制的底层原理和适用场景,能够帮助我们在实际开发中做出正确的技术选择,编写出高性能、线程安全的并发程序。随着 Java 并发编程的不断发展,掌握这些核心概念将为我们应对更复杂的并发挑战奠定坚实的基础。
在实际应用中,我们应该根据具体的业务场景和性能要求,选择最合适的并发控制机制,并始终遵循并发编程的最佳实践,确保程序的正确性和高效性。