1. 线程池相关工具类
1.1 Executor
和 ExecutorService
-
Executor
:这是一个接口,用于定义提交任务的一种机制。通过Executor
,开发者可以将任务的执行与任务的提交分离。 -
ExecutorService
:继承自Executor
接口,增加了一些管理任务执行和生命周期的方法。ExecutorService
允许开发者管理线程池的生命周期,执行异步任务,并获取任务的结果。常见的实现类包括:
ThreadPoolExecutor
:一个功能强大的线程池实现,允许配置线程池的核心线程数、最大线程数、任务队列等参数。ScheduledThreadPoolExecutor
:支持定时和周期性任务调度的线程池。
示例代码:
ExecutorService executor = Executors.newFixedThreadPool(10); executor.submit(() -> { System.out.println("Task executed"); }); executor.shutdown();
1.2 ForkJoinPool
ForkJoinPool
是 Java 7 引入的一种特殊的线程池,设计用于递归任务的并行执行。它基于工作窃取算法(Work-Stealing Algorithm),能够高效地处理那些可以分解成多个子任务的工作负载。
RecursiveTask
:用于有返回值的递归任务。RecursiveAction
:用于没有返回值的递归任务。
示例代码:
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Integer> task = forkJoinPool.submit(new RecursiveTaskExample());
Integer result = task.join();
2. 同步工具类
2.1 CountDownLatch
CountDownLatch
是一种同步工具类,允许一个或多个线程等待,直到其他线程完成一组操作。它通过一个计数器实现,当计数器的值降为零时,所有等待的线程将被唤醒。
-
典型应用场景:用于确保某些活动直到其他所有依赖的活动完成之后再执行,例如等待多个线程完成计算后再汇总结果。
示例代码:
CountDownLatch latch = new CountDownLatch(3); Runnable task = () -> { System.out.println(Thread.currentThread().getName() + " is working"); latch.countDown(); }; new Thread(task).start(); new Thread(task).start(); new Thread(task).start(); latch.await(); System.out.println("All tasks completed");
2.2 CyclicBarrier
CyclicBarrier
是另一种用于线程同步的工具类,允许一组线程互相等待,直到所有线程都到达某个共同的障碍点。CyclicBarrier
与 CountDownLatch
的不同之处在于它可以重复使用,即在所有线程到达障碍点并执行完后,CyclicBarrier
可以被重置以供后续使用。
-
典型应用场景:用于在并行处理时,确保多个线程在执行下一步操作之前达成同步,如并行分块处理。
示例代码:
CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All parties are arrived at barrier, let's play"); }); Runnable task = () -> { try { System.out.println(Thread.currentThread().getName() + " is waiting at barrier"); barrier.await(); } catch (Exception e) { e.printStackTrace(); } }; new Thread(task).start(); new Thread(task).start(); new Thread(task).start();
2.3 Semaphore
Semaphore
是一个计数信号量,它可以控制同时访问特定资源的线程数量。信号量主要用于管理对有限资源的访问,例如数据库连接池、文件系统等。
-
典型应用场景:限制对某些资源的访问,例如只允许一次最多五个线程访问数据库。
示例代码:
Semaphore semaphore = new Semaphore(3); Runnable task = () -> { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " got the permit"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); System.out.println(Thread.currentThread().getName() + " released the permit"); } }; new Thread(task).start(); new Thread(task).start(); new Thread(task).start(); new Thread(task).start(); new Thread(task).start();
2.4 ReentrantLock
ReentrantLock
是一个可重入的锁,提供了比 synchronized
更加灵活的锁机制。它允许显式地获取和释放锁,并提供了与 Condition
对象结合使用的功能,以实现更加复杂的线程间同步。
-
典型应用场景:用于需要显式控制锁获取和释放的场景,特别是在需要尝试加锁或带超时的加锁操作时。
示例代码:
ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); Runnable task = () -> { lock.lock(); try { System.out.println(Thread.currentThread().getName() + " acquired the lock"); condition.await(); System.out.println(Thread.currentThread().getName() + " resumed"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }; new Thread(task).start();
3. 并发集合类
3.1 ConcurrentHashMap
ConcurrentHashMap
是线程安全的 HashMap
实现,它使用了一种细粒度的锁机制,允许多个线程并发地读写操作。与传统的 Hashtable
不同,ConcurrentHashMap
具有更好的并发性能,因为它不会对整个表加锁,而是对各个桶(bucket)进行细粒度加锁。
-
典型应用场景:用于在高并发场景下存储和访问数据,例如缓存、计数器等。
示例代码:
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); map.put("key1", 1); map.put("key2", 2); System.out.println(map.get("key1"));
3.2 CopyOnWriteArrayList
CopyOnWriteArrayList
是一种线程安全的列表实现,它通过在每次修改时复制整个底层数组来实现线程安全。这种机制特别适合读多写少的场景,因为读操作无需加锁,且不会阻塞。
-
典型应用场景:用于需要频繁读取但很少修改的列表场景,例如系统配置、事件监听器列表等。
示例代码:
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(); list.add("Hello"); list.add("World"); for (String s : list) { System.out.println(s); }
3.3 BlockingQueue
BlockingQueue
是一种支持线程安全操作的队列,提供了阻塞的插入和移除方法。常见的实现包括 ArrayBlockingQueue
、LinkedBlockingQueue
、PriorityBlockingQueue
等。
-
典型应用场景:用于生产者-消费者模式,生产者将数据放入队列,消费者从队列中获取数据进行处理。
示例代码:
BlockingQueue<String> queue = new LinkedBlockingQueue<>(10); new Thread(() -> { try { queue.put("data"); System.out.println("Produced data"); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try { String data = queue.take(); System.out.println("Consumed " + data); } catch (InterruptedException e) { e.printStackTrace(); } }).start();
4. 原子类
4.1 AtomicInteger
AtomicInteger
是一个提供原子操作的 int
类型包装类,支持线程安全的递增、递减和更新操作。它通过底层的 CAS
(Compare-And-Swap)操作实现线程安全。
-
典型应用场景:用于计数器、标识符生成器等需要高并发下的原子操作场景。
示例代码:
AtomicInteger atomicInteger = new AtomicInteger(0); int newValue = atomicInteger.incrementAndGet(); System.out.println(newValue);
4.2 AtomicBoolean
, AtomicLong
, `
AtomicReference`
AtomicBoolean
:提供原子操作的boolean
类型。AtomicLong
:提供原子操作的long
类型。AtomicReference
:提供对引用对象的原子更新操作。
5. 并发辅助类
5.1 Exchanger
Exchanger
是一种同步点,两个线程可以在此点交换数据。线程在 Exchanger
上进行 exchange
操作时将数据传递给对方,并接收对方的数据。
-
典型应用场景:用于两个线程之间的数据交换,如生产者和消费者之间的缓冲区交换。
示例代码:
Exchanger<String> exchanger = new Exchanger<>(); new Thread(() -> { try { String data = "Data from Thread A"; String received = exchanger.exchange(data); System.out.println("Thread A received: " + received); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(() -> { try { String data = "Data from Thread B"; String received = exchanger.exchange(data); System.out.println("Thread B received: " + received); } catch (InterruptedException e) { e.printStackTrace(); } }).start();
5.2 Phaser
Phaser
是一种更灵活的同步屏障,允许线程动态地参与或退出同步。它是 CyclicBarrier
和 CountDownLatch
的增强版本,适用于复杂的分阶段任务。
-
典型应用场景:用于需要分阶段同步或变动参与者的场景。
示例代码:
Phaser phaser = new Phaser(1); // 注册主线程 for (int i = 0; i < 3; i++) { phaser.register(); new Thread(() -> { System.out.println(Thread.currentThread().getName() + " arrived at phase 1"); phaser.arriveAndAwaitAdvance(); System.out.println(Thread.currentThread().getName() + " arrived at phase 2"); phaser.arriveAndAwaitAdvance(); }).start(); } phaser.arriveAndDeregister(); // 主线程到达并注销
总结
Java 提供了丰富的并发工具类来帮助开发者应对多线程编程的挑战。从线程池管理到同步机制,再到并发集合和原子操作,每种工具类都有其特定的应用场景和优点,这些工具类位于 java.util.concurrent
包中,涵盖了从线程池、同步机制到并发集合的广泛功能。