Java JUC(Java Util Concurrent)是 Java 平台提供的并发编程工具包,它提供了一系列的工具类和接口,用于简化多线程编程。JUC 中的类和接口都是基于 Java 平台的底层并发原语(如锁、信号量、原子变量等)实现的,可以帮助开发者更加方便和安全地完成多线程编程。
JUC 中的常用类和接口
1. Lock 和 ReentrantLock
Lock 接口是 Java 并发包中提供的一种比 synchronized 更加灵活的锁机制。它提供了更加细粒度的控制,可以实现更加复杂的线程同步操作。ReentrantLock 是 Lock 接口的一个实现类,它提供了与 synchronized 相同的互斥性和内存可见性,同时还提供了更多的高级功能,如可重入锁、公平锁等。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockDemo {private Lock lock = new ReentrantLock();public void print() {lock.lock();try {// 线程安全的代码System.out.println(Thread.currentThread().getName() + " is running");} finally {lock.unlock();}}
}
2. Condition
Condition 接口是 Lock 接口提供的一个高级功能,它可以用于实现线程之间的通信。一个 Condition 对象可以和一个 Lock 对象关联,当一个线程调用 Condition 的 await() 方法时,它会释放掉与这个 Condition 对象关联的 Lock 对象的锁,并进入等待状态;当另一个线程调用 Condition 的 signal() 或 signalAll() 方法时,它会通知一个或所有正在等待的线程恢复执行。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class ConditionDemo {private Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();private int count = 0;public void produce() {lock.lock();try {while (count >= 10) {condition.await();}count++;System.out.println(Thread.currentThread().getName() + " produce, count = " + count);condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}public void consume() {lock.lock();try {while (count <= 0) {condition.await();}count--;System.out.println(Thread.currentThread().getName() + " consume, count = " + count);condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}
}
3. Semaphore
Semaphore 是一种计数信号量,它可以用于控制同时访问某个资源的线程数量。Semaphore 维护了一个计数器,每当一个线程访问该资源时,计数器就会减一;当计数器为零时,所有试图访问该资源的线程都会被阻塞,直到计数器大于零。
import java.util.concurrent.Semaphore;public class SemaphoreDemo {private Semaphore semaphore = new Semaphore(5);public void access() {try {semaphore.acquire();// 线程安全的代码System.out.println(Thread.currentThread().getName() + " is running");} catch (InterruptedException e) {e.printStackTrace();} finally {semaphore.release();}}
}
4. CountDownLatch
CountDownLatch 是一种同步工具类,它可以让一个或多个线程等待其他线程完成操作后再继续执行。CountDownLatch 维护了一个计数器,线程调用它的 await() 方法会阻塞,直到计数器变为零;而其他线程完成操作后,可以调用 CountDownLatch 的 countDown() 方法将计数器减一。
import java.util.concurrent.CountDownLatch;public class CountDownLatchDemo {private CountDownLatch countDownLatch = new CountDownLatch(3);public void task() {try {// 模拟耗时操作Thread.sleep((long) (Math.random() * 1000));System.out.println(Thread.currentThread().getName() + " is running");} catch (InterruptedException e) {e.printStackTrace();} finally {countDownLatch.countDown();}}public void start() {for (int i = 0; i < 3; i++) {new Thread(this::task).start();}try {countDownLatch.await();System.out.println("All tasks have been completed");} catch (InterruptedException e) {e.printStackTrace();}}
}
5. CyclicBarrier
CyclicBarrier 是一种同步工具类,它可以让一组线程在达到某个共同点之前相互等待。CyclicBarrier 维护了一个计数器和一个栅栏点,每当一个线程到达栅栏点时,计数器就会减一;当计数器为零时,所有线程就可以继续执行。
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class CyclicBarrierDemo {private CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {System.out.println("All threads have arrived at the barrier");});public void task() {try {// 模拟耗时操作Thread.sleep((long) (Math.random() * 1000));System.out.println(Thread.currentThread().getName() + " has arrived at the barrier");cyclicBarrier.await();System.out.println(Thread.currentThread().getName() + " is running");} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}public void start() {for (int i = 0; i < 3; i++) {new Thread(this::task).start();}}
}
JUC 中的常用工具类
1. Executors
Executors 是一个工具类,用于创建线程池。它提供了一些静态方法,可以方便地创建不同类型的线程池。常用的方法有:
- newFixedThreadPool(int nThreads):创建一个固定大小的线程池,该线程池中的线程数始终为 nThreads。
- newCachedThreadPool():创建一个缓存线程池,该线程池可以根据需要创建新的线程,但在有可用线程时重用旧线程。
- newSingleThreadExecutor():创建一个单线程池,该线程池中始终只有一个线程在工作。
- newScheduledThreadPool(int corePoolSize):创建一个定时任务线程池,该线程池可以在指定的延迟时间后执行任务,也可以按照固定的时间间隔执行任务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ExecutorsDemo {private ExecutorService executorService = Executors.newFixedThreadPool(5);public void execute() {executorService.execute(() -> {// 线程安全的代码System.out.println(Thread.currentThread().getName() + " is running");});}public void shutdown() {executorService.shutdown();}
}
2. Future 和 FutureTask
Future 接口表示一个异步计算的结果,它提供了一些方法,可以查询计算是否完成、等待计算完成并获取结果。FutureTask 是 Future 接口的一个实现类,它可以用于异步执行任务,并且可以在任务执行完成后获取任务的执行结果。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class FutureTaskDemo {private FutureTask<Integer> futureTask = new FutureTask<>(() -> {// 模拟耗时操作Thread.sleep((long) (Math.random() * 1000));return 1;});public void start() {new Thread(futureTask).start();}public void get() {try {int result = futureTask.get();System.out.println("Result: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();}}
}
3. ConcurrentHashMap
ConcurrentHashMap 是一个线程安全的哈希表,它可以在高并发的情况下提供更好的性能。它的实现原理是将整个哈希表分成多个段,每个段都是一个独立的哈希表,可以独立地进行添加、删除、修改等操作。这样,当多个线程同时访问不同的段时,就可以实现真正的并行操作,从而提高了并发性能。
import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapDemo {private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();public void put(String key, int value) {map.put(key, value);}public int get(String key) {return map.get(key);}
}
JUC 中的高级特性
1. AQS
AQS(AbstractQueuedSynchronizer)是 JUC 中的一个重要类,它提供了一种通用的同步框架,可以用于实现各种同步器,如锁、信号量、倒计时门栓等。AQS 的核心思想是基于一个先进先出(FIFO)的队列,来管理等待获取同步状态的线程。当一个线程获取同步状态失败时,它会被封装成一个节点,然后加入到等待队列中,等待其他线程释放同步状态后再次尝试获取。
2. ForkJoin
ForkJoin 框架是 JUC 中的一个高性能并行计算框架,它可以将一个大任务拆分成多个小任务,并行地执行这些小任务,最后将小任务的结果合并成大任务的结果。ForkJoin 框架的核心思想是“工作窃取”,即当一个线程的任务执行完毕后,它可以从其他线程的任务队列中窃取一个任务来执行,以此来实现负载均衡。
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;public class ForkJoinDemo extends RecursiveTask<Integer> {private int start;private int end;public ForkJoinDemo(int start, int end) {this.start = start;this.end = end;}@Overrideprotected Integer compute() {if (end - start <= 100) {int sum = 0;for (int i = start; i <= end; i++) {sum += i;}return sum;} else {int mid = (start + end) / 2;ForkJoinDemo left = new ForkJoinDemo(start, mid);ForkJoinDemo right = new ForkJoinDemo(mid + 1, end);left.fork();right.fork();return left.join() + right.join();}}public static void main(String[] args) {ForkJoinPool forkJoinPool = new ForkJoinPool();ForkJoinDemo task = new ForkJoinDemo(1, 1000);Integer result = forkJoinPool.invoke(task);System.out.println("Result: " + result);}
}
总结
Java JUC 提供了一系列的工具类和接口,用于简化多线程编程。在实际开发中,我们应该根据具体的业务需求选择合适的工具类和接口,以提高程序的并发性能和可靠性。同时,我们还应该遵守多线程编程的最佳实践,如避免死锁、竞态条件等问题,以确保程序的正确性和稳定性。
公众号请关注"果酱桑", 一起学习,一起进步!