当前位置: 首页 > news >正文

java线程同步工具:`synchronized`、`ReentrantLock`与其他并发工具的对比与应用

在Java多线程编程中,线程同步和并发控制是确保程序正确性和性能的关键。Java提供了多种同步工具,包括内置的synchronized关键字、ReentrantLock以及java.util.concurrent包中的高级并发工具。这些工具各有特点,适用于不同的并发场景。本文将详细对比synchronizedReentrantLock,并介绍其他常用的线程工具,帮助开发者根据需求选择合适的工具。

一、synchronizedReentrantLock的对比
1. 基本概念
  • synchronized:
    • Java的内置关键字,基于JVM的监视器锁(monitor lock)实现。
    • 用于方法或代码块的同步,自动获取和释放锁。
    • 是隐式锁,依赖JVM管理,代码简洁但灵活性较低。
  • ReentrantLock:
    • java.util.concurrent.locks包中的显式锁,基于AQS(AbstractQueuedSynchronizer)实现。
    • 需要手动调用lock()unlock()来获取和释放锁。
    • 提供更高的灵活性和功能,但需要开发者显式管理锁的释放。
2. 主要区别
特性synchronizedReentrantLock
锁的类型内置锁,JVM级别实现显式锁,基于AQS实现
可重入性支持(同一线程可多次获取锁)支持(同一线程可多次获取锁)
灵活性较低,自动获取/释放锁较高,支持更多高级功能
锁的获取方式自动获取,阻塞直到获取可选择阻塞(lock())或非阻塞(tryLock()
公平性非公平锁(不保证线程获取锁的顺序)可配置公平锁(new ReentrantLock(true))或非公平锁
条件变量单一条件(wait()/notify()支持多个Condition对象(更灵活的等待/通知)
中断响应不支持锁获取中断支持(lockInterruptibly()
超时机制不支持超时获取锁支持(tryLock(long, TimeUnit)
性能现代JVM优化后性能较好在高并发场景下通常更高效
释放锁的方式自动释放(离开同步块或方法)需手动调用unlock(),否则可能导致死锁
异常处理异常后自动释放锁需在finally块中显式释放锁
3. 功能对比
  • synchronized:
    • 简单易用,适合简单的同步场景。
    • 使用wait()notify()/notifyAll()实现线程间的条件等待,功能有限。
    • 无法中断等待锁的线程或设置锁超时。
    • 示例:
      class Counter {private int count = 0;public synchronized void increment() {count++;}public synchronized int getCount() {return count;}
      }
      
  • ReentrantLock:
    • 提供非阻塞锁获取(tryLock())、中断锁获取(lockInterruptibly())和超时机制。
    • 支持多个Condition对象,适合复杂条件等待场景。
    • 可配置公平锁,减少线程饥饿。
    • 示例:
      import java.util.concurrent.locks.ReentrantLock;
      class Counter {private int count = 0;private final ReentrantLock lock = new ReentrantLock();public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}public int getCount() {lock.lock();try {return count;} finally {lock.unlock();}}
      }
      
4. 使用场景
  • synchronized: 适合简单同步场景,代码简洁,适用于共享变量保护或方法同步。
  • ReentrantLock: 适合需要高级功能的场景,如超时控制、中断响应、公平锁或多条件等待(如生产者-消费者模型)。
    • 示例:
      ReentrantLock lock = new ReentrantLock();
      Condition condition = lock.newCondition();
      void produce() {lock.lock();try {while (buffer.isFull()) {condition.await();}buffer.add(item);condition.signal();} finally {lock.unlock();}
      }
      
5. 性能
  • 早期Java中,synchronized是重量级锁,性能较低。现代JVM(Java 6及以上)通过锁升级(偏向锁→轻量级锁→重量级锁)优化,性能接近ReentrantLock
  • ReentrantLock在高并发场景下通常更高效,尤其在需要公平锁或复杂条件等待时。
6. 选择建议
  • 优先使用synchronized,因为它简单且现代JVM优化良好。
  • 当需要中断、超时、公平锁或多条件等待时,选择ReentrantLock
二、其他常用线程工具

Java的java.util.concurrent包提供了丰富的并发工具,适用于更复杂的多线程场景。以下是常用的工具及其应用:

1. 线程池相关工具
  • ExecutorService / Executors:
    • 管理线程池,支持任务提交、批量执行和线程复用。
    • 常用实现:
      • Executors.newFixedThreadPool(int n): 固定大小线程池。
      • Executors.newCachedThreadPool(): 动态调整线程数。
      • Executors.newSingleThreadExecutor(): 单线程顺序执行。
      • Executors.newScheduledThreadPool(int n): 支持定时任务。
    • 使用场景:批量任务处理、后台任务、定时任务。
    • 示例:
      ExecutorService executor = Executors.newFixedThreadPool(4);
      executor.submit(() -> System.out.println("Task executed"));
      executor.shutdown();
      
  • ForkJoinPool:
    • 专为分治算法设计,基于工作窃取算法。
    • 使用场景:并行排序、矩阵计算。
    • 示例:
      ForkJoinPool pool = ForkJoinPool.commonPool();
      RecursiveTask<Integer> task = new MyTask();
      Integer result = pool.invoke(task);
      
2. 并发集合
  • ConcurrentHashMap:
    • 线程安全的哈希表,锁粒度细,适合高并发读写。
    • 使用场景:共享键值存储。
    • 示例:
      ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
      map.put("key", 1);
      map.computeIfPresent("key", (k, v) -> v + 1);
      
  • CopyOnWriteArrayList / CopyOnWriteArraySet:
    • 写时复制,适合读多写少场景。
    • 使用场景:事件监听器列表、只读配置。
    • 示例:
      CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
      list.add("item");
      
  • BlockingQueue:
    • 线程安全队列,支持阻塞操作。
    • 实现类:ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueueSynchronousQueue
    • 使用场景:生产者-消费者模型。
    • 示例:
      BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
      queue.put("task");
      String task = queue.take();
      
3. 锁和同步工具
  • ReadWriteLock / ReentrantReadWriteLock:
    • 读写分离锁,允许多线程读、单线程写。
    • 使用场景:缓存系统、数据库访问。
    • 示例:
      ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
      rwLock.readLock().lock();
      try {// 读操作
      } finally {rwLock.readLock().unlock();
      }
      
  • Semaphore:
    • 控制同时访问资源的线程数。
    • 使用场景:数据库连接池、限流。
    • 示例:
      Semaphore semaphore = new Semaphore(3);
      semaphore.acquire();
      try {// 访问资源
      } finally {semaphore.release();
      }
      
  • CountDownLatch:
    • 让线程等待其他线程完成操作。
    • 使用场景:多线程任务协调。
    • 示例:
      CountDownLatch latch = new CountDownLatch(3);
      new Thread(() -> {// 任务latch.countDown();
      }).start();
      latch.await();
      
  • CyclicBarrier:
    • 让线程组在屏障点同步。
    • 使用场景:多阶段计算。
    • 示例:
      CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("All reached"));
      new Thread(() -> {barrier.await();
      }).start();
      
  • Phaser:
    • 动态管理多阶段同步。
    • 使用场景:复杂多阶段任务。
    • 示例:
      Phaser phaser = new Phaser(3);
      new Thread(() -> {phaser.arriveAndAwaitAdvance();
      }).start();
      
4. 原子操作类
  • AtomicInteger / AtomicLong / AtomicBoolean:
    • 基于CAS的无锁原子操作。
    • 使用场景:计数器、状态标志。
    • 示例:
      AtomicInteger counter = new AtomicInteger(0);
      counter.incrementAndGet();
      
  • AtomicReference:
    • 原子更新复杂对象。
    • 示例:
      AtomicReference<String> ref = new AtomicReference<>("old");
      ref.compareAndSet("old", "new");
      
5. 其他工具
  • LockSupport:
    • 提供低级线程控制(park()/unpark())。
    • 使用场景:自定义锁实现。
    • 示例:
      LockSupport.park();
      LockSupport.unpark(thread);
      
  • ThreadLocal:
    • 为每个线程提供独立变量副本。
    • 使用场景:线程本地存储。
    • 示例:
      ThreadLocal<Integer> local = ThreadLocal.withInitial(() -> 0);
      local.set(1);
      
三、总结与选择建议
  • synchronizedReentrantLock:
    • synchronized适合简单同步场景,代码简洁,依赖JVM优化。
    • ReentrantLock提供高级功能(如中断、超时、公平锁),适合复杂场景。
  • 其他并发工具:
    • 线程池(ExecutorServiceForkJoinPool)适合任务管理和并行计算。
    • 并发集合(ConcurrentHashMapBlockingQueue等)优化高并发数据结构操作。
    • 高级锁和同步器(ReadWriteLockSemaphoreCountDownLatch等)提供灵活的同步控制。
    • 原子类(AtomicInteger等)适合高效无锁操作。
    • ThreadLocalLockSupport解决特定场景需求。

开发者应根据场景需求选择工具:简单同步用synchronized,复杂场景用ReentrantLock或并发包工具,高并发数据操作用并发集合,任务管理用线程池。


http://www.lryc.cn/news/611362.html

相关文章:

  • Kafka自动消费消息软件(自动化测试Kafka)
  • python的高校班级管理系统
  • VUE+SPRINGBOOT从0-1打造前后端-前后台系统-登录实现
  • SpringCloud学习------Gateway详解
  • 将普通用户添加到 Docker 用户组
  • 虚幻GAS底层原理解剖二 (GE)
  • 如何用分布式架构视角理解宇宙稳定性?从精细调参到微服务的类比思考
  • 天津大学2024-2025 预推免 机试题目(第二批)
  • 关于内核启动的optee: probe of firmware: optee failed with error -22 固件拉起失败的问题
  • 《软件测试与质量控制》实验报告四 性能测试
  • HPE磁盘阵列管理01——MSA和SMU
  • “Why“比“How“更重要:层叠样式表CSS
  • sql调优总结
  • 分布式选举算法:Bully、Raft、ZAB
  • 【深度学习新浪潮】TripoAI是一款什么样的产品?
  • ORACLE多表查询
  • GaussDB 常见问题-集中式
  • 【带root权限】中兴ZXV10 B863AV3.2-M_S905L3A处理器刷当贝纯净版固件教程_ROM包_刷机包_线刷包
  • Java set集合讲解
  • 最长连续序列(每天刷力扣hot100系列)
  • python学智能算法(三十三)|SVM-构建软边界拉格朗日方程
  • 利用 Radius Resource Types 扩展平台工程能力
  • avue---upload 图片上传
  • Vue3核心语法进阶(Props)
  • 从汇编角度揭秘C++构造函数(1)
  • 【Lua】题目小练8
  • 超越注意力机制
  • Augmodo AI:零售门店智能货架管理平台
  • 8月5号打卡
  • Java: jwt 入门介绍(Introduction to JSON Web Tokens)