JUC包下的类
1.原子操作类(Atomic)
在Java运算的多线程环境下进行运算若没有进行额外的同步操作,就是线程不安全的多线程并发共享必然会遇到问题所以可以用原子类解决
(1)AtomicInteger
提供了一个原子性的整数变量,可以进行原子性的加减操作。
(2)AtomicLong
提供了一个原子性的长整型变量
(3)AtomicBoolean
提供了一个原子性的布尔值
使用方法:
public class AtomicIntegerTest1 {
public static void main(String[] args) {
int temValue = 0;
AtomicInteger i = new AtomicInteger(0);
temValue = i.getAndSet(12);
System.out.println("temValue:" + temValue + "; i:" + i);
temValue = i.getAndIncrement();
System.out.println("temValue:" + temValue + "; i:" + i);
temValue = i.getAndAdd(-10);
System.out.println("temValue:" + temValue + "; i:" + i);
}
}
//输出结果
//temValue:0; i:12
//temValue:12; i:13
//temValue:13; i:3
(4)AtomicReference
提供了一个可以原子性更新的对象引用
使用方法:
public class DebitCard {
private final String name;
private final int account;
public DebitCard(String name, int account) {
this.name = name;
this.account = account;
}
// getters and toString() methods
}
AtomicReference<DebitCard> ref = new AtomicReference<>(new DebitCard("zhangSan", 10));
// 使用AtomicReference原子地更新账户现金数额
ref.updateAndGet(debitCard -> new DebitCard(debitCard.getName(), debitCard.getAccount() + 10));
(5)AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
分别提供了数组形式的原子操作支持
使用方法:
public class AtomicIntegerArrayTest {
public static void main(String[] args) {
int temValue = 0;
int[] nums = {-2, -1, 1, 2, 3, 4};
AtomicIntegerArray i = new AtomicIntegerArray(nums);
for (int j = 0; j < nums.length; j++) {
System.out.println(i.get(j));
}
temValue = i.getAndSet(0, 2);
System.out.println("temValue:" + temValue + "; i:" + i);
temValue = i.getAndIncrement(0);
System.out.println("temValue:" + temValue + "; i:" + i);
temValue = i.getAndAdd(0, 5);
System.out.println("temValue:" + temValue + "; i:" + i);
}
}
2.同步器(Synchronizers)
(1)CountDownLatch
让某一个线程等待多个线程的操作完成之后再执行。它可以使一个或多个线程等待一组事件的发生,而其他的线程则可以触发这组事件。计数器只能够被减少,不能够被增加。
使用方法:
package com.heima;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) {
// 定义一个计数器,初始值为3,表示有3个线程需要完成任务
CountDownLatch latch = new CountDownLatch(3);
// 创建3个工作线程
for (int i = 0; i < 3; i++) {
new Worker(latch, "Worker-" + (i + 1)).start();
}
try {
// 主线程等待所有工作线程完成任务
System.out.println("主线程正在等待所有工作线程完成任务...");
latch.await();
System.out.println("所有工作线程已完成任务,主线程继续执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
static class Worker extends Thread {
private final CountDownLatch latch;
public Worker(CountDownLatch latch, String name) {
super(name);
this.latch = latch;
}
@Override
public void run() {
System.out.println(getName() + " 开始执行任务...");
try {
// 模拟任务执行时间
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + " 任务完成");
// 任务完成后,计数器减1
latch.countDown();
}
}
}
运行结果:
可以发现无论多少次主线程都是等所有线程运行完最后运行
(2)CyclicBarrier
让一组线程到达一个屏障点后被阻塞,直到最后一个线程到达屏障时,屏障才会打开,所有被阻塞的线程开始继续执行。与 CountDownLatch 不同,CyclicBarrier 可以被重置并重复使用。
package com.heima;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierExample {
public static void main(String[] args) {
// 定义一个CyclicBarrier,初始值为3,表示有3个线程需要到达屏障点
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程已到达屏障点,开始下一步操作");
});
// 创建3个工作线程
for (int i = 0; i < 3; i++) {
new Worker(barrier, "Worker-" + (i + 1)).start();
}
}
static class Worker extends Thread {
private final CyclicBarrier barrier;
public Worker(CyclicBarrier barrier, String name) {
super(name);
this.barrier = barrier;
}
@Override
public void run() {
System.out.println(getName() + " 开始执行任务...");
try {
// 模拟任务执行时间
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getName() + " 任务完成,等待其他线程到达屏障点");
try {
// 等待其他线程到达屏障点
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(getName() + " 继续执行后续任务");
}
}
}
区别:
CountDownLatch 适用于一个或多个线程等待其他线程完成任务的场景,是一次性的。
CyclicBarrier 适用于多个线程互相等待,直到所有线程都到达一个公共屏障点的场景,可以重用。
根据业务场景自行选择
(3)Semaphore
用来控制同时访问特定资源的线程数量,通过协调各个线程以保证合理的使用资源。它通过维护一组许可证来实现这一点。线程在访问资源之前需要获取一个许可证,使用完资源后释放许可证,这样其他线程就可以获取并使用该许可证。
代码实现:
package com.heima;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreExample {
public static void main(String[] args) {
// 创建一个具有3个许可证的Semaphore
Semaphore semaphore = new Semaphore(3, true); // 公平模式
// 创建5个工作线程
for (int i = 0; i < 5; i++) {
new Worker(semaphore, "Worker-" + (i + 1)).start();
}
}
static class Worker extends Thread {
private final Semaphore semaphore;
public Worker(Semaphore semaphore, String name) {
super(name);
this.semaphore = semaphore;
}
@Override
public void run() {
try {
// 获取一个许可证
semaphore.acquire();
System.out.println(getName() + " 获取到许可证,开始执行任务...");
// 模拟任务执行时间
Thread.sleep((long) (Math.random() * 1000));
System.out.println(getName() + " 任务完成,释放许可证");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放一个许可证
semaphore.release();
}
}
}
}
(4)Phaser
它提供了一种灵活的方式来管理多个线程之间的同步。与 CountDownLatch 和 CyclicBarrier 相比,Phaser 更加灵活,支持动态注册和注销参与者,以及多阶段同步。
代码实现:
import java.util.concurrent.Phaser;
public class PhaserExample {
public static void main(String[] args) {
// 创建一个初始参与者数量为3的Phaser
Phaser phaser = new Phaser(3);
// 创建3个工作线程
for (int i = 0; i < 3; i++) {
new Worker(phaser, "Worker-" + (i + 1)).start();
}
}
static class Worker extends Thread {
private final Phaser phaser;
public Worker(Phaser phaser, String name) {
super(name);
this.phaser = phaser;
}
@Override
public void run() {
try {
// 第一阶段
System.out.println(getName() + " 开始第一阶段任务...");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(getName() + " 第一阶段任务完成,等待其他线程到达第一阶段");
phaser.arriveAndAwaitAdvance();
// 第二阶段
System.out.println(getName() + " 开始第二阶段任务...");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(getName() + " 第二阶段任务完成,等待其他线程到达第二阶段");
phaser.arriveAndAwaitAdvance();
// 注销参与者
phaser.arriveAndDeregister();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.阻塞队列(Blocking Queues)
(1)ArrayBlockingQueue
基于数组实现,提供了线程安全的插入、移除和访问操作,并且在队列满或空时会阻塞生产者或消费者线程。这使得它非常适合用于生产者-消费者模型中的线程间通信和同步
代码实现:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class ArrayBlockingQueueExample {
public static void main(String[] args) {
// 创建一个容量为10的ArrayBlockingQueue
ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
// 创建生产者线程
Thread producer = new Thread(new Producer(queue), "Producer");
// 创建消费者线程
Thread consumer = new Thread(new Consumer(queue), "Consumer");
// 启动线程
producer.start();
consumer.start();
}
static class Producer implements Runnable {
private final ArrayBlockingQueue<Integer> queue;
public Producer(ArrayBlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + " 生产: " + i);
queue.put(i);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
private final ArrayBlockingQueue<Integer> queue;
public Consumer(ArrayBlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
Integer item = queue.take();
System.out.println(Thread.currentThread().getName() + " 消费: " + item);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(2)LinkedBlockingQueue
Java 并发包中的一个基于链表结构的阻塞队列。与 ArrayBlockingQueue 不同LinkedBlockingQueue 是无界的(默认情况下),但也可以设置一个有限的容量。它提供了线程安全的插入、移除和访问操作,并且在队列满或空时会阻塞生产者或消费者线程。这使得它非常适合用于生产者-消费者模型中的线程间通信和同步。
代码实现:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class LinkedBlockingQueueExample {
public static void main(String[] args) {
// 创建一个容量为10的LinkedBlockingQueue
LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
// 创建生产者线程
Thread producer = new Thread(new Producer(queue), "Producer");
// 创建消费者线程
Thread consumer = new Thread(new Consumer(queue), "Consumer");
// 启动线程
producer.start();
consumer.start();
}
static class Producer implements Runnable {
private final LinkedBlockingQueue<Integer> queue;
public Producer(LinkedBlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName() + " 生产: " + i);
queue.put(i);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
private final LinkedBlockingQueue<Integer> queue;
public Consumer(LinkedBlockingQueue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
Integer item = queue.take();
System.out.println(Thread.currentThread().getName() + " 消费: " + item);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(3)PriorityBlockingQueue
是 一个无界并发队列,它基于优先堆实现。PriorityBlockingQueue 中的元素按照其自然顺序或通过提供的 Comparator 进行排序。这意味着每次从队列中取出的元素都是当前队列中优先级最高的元素。
代码实现:
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
class Task implements Comparable<Task> {
private int id;
private int priority;
public Task(int id, int priority) {
this.id = id;
this.priority = priority;
}
public int getId() {
return id;
}
public int getPriority() {
return priority;
}
@Override
public int compareTo(Task other) {
return Integer.compare(this.priority, other.priority);
}
@Override
public String toString() {
return "Task{" +
"id=" + id +
", priority=" + priority +
'}';
}
}
public class PriorityBlockingQueueExample {
public static void main(String[] args) {
// 创建一个PriorityBlockingQueue
PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();
// 创建生产者线程
Thread producer = new Thread(new Producer(queue), "Producer");
// 创建消费者线程
Thread consumer = new Thread(new Consumer(queue), "Consumer");
// 启动线程
producer.start();
consumer.start();
}
static class Producer implements Runnable {
private final PriorityBlockingQueue<Task> queue;
public Producer(PriorityBlockingQueue<Task> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
int priority = (int) (Math.random() * 10);
Task task = new Task(i, priority);
System.out.println(Thread.currentThread().getName() + " 生产: " + task);
queue.put(task);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
private final PriorityBlockingQueue<Task> queue;
public Consumer(PriorityBlockingQueue<Task> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
Task task = queue.take();
System.out.println(Thread.currentThread().getName() + " 消费: " + task);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(4)DelayQueue
是 一个无界阻塞队列,专门用于处理延迟任务。DelayQueue 中的元素必须实现 Delayed 接口,该接口定义了一个 getDelay 方法来获取剩余的延迟时间和一个 compareTo 方法来进行元素的排序。DelayQueue 只允许在延迟时间到期后才能从队列中取出元素
代码实现
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class DelayQueueExample {
public static void main(String[] args) {
// 创建一个DelayQueue
DelayQueue<DelayedTask> queue = new DelayQueue<>();
// 创建生产者线程
Thread producer = new Thread(new Producer(queue), "Producer");
// 创建消费者线程
Thread consumer = new Thread(new Consumer(queue), "Consumer");
// 启动线程
producer.start();
consumer.start();
}
static class DelayedTask implements Delayed {
private final long delayTime; // 延迟时间(毫秒)
private final long expireTime; // 到期时间
private final AtomicInteger idGenerator = new AtomicInteger(0);
private final int id;
public DelayedTask(long delayTime) {
this.delayTime = delayTime;
this.expireTime = System.currentTimeMillis() + delayTime;
this.id = idGenerator.getAndIncrement();
}
@Override
public long getDelay(TimeUnit unit) {
long remaining = expireTime - System.currentTimeMillis();
return unit.convert(remaining, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed other) {
if (this.getDelay(TimeUnit.MILLISECONDS) < other.getDelay(TimeUnit.MILLISECONDS)) {
return -1;
} else if (this.getDelay(TimeUnit.MILLISECONDS) > other.getDelay(TimeUnit.MILLISECONDS)) {
return 1;
} else {
return 0;
}
}
@Override
public String toString() {
return "DelayedTask{" +
"id=" + id +
", delayTime=" + delayTime +
", expireTime=" + expireTime +
'}';
}
}
static class Producer implements Runnable {
private final DelayQueue<DelayedTask> queue;
public Producer(DelayQueue<DelayedTask> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
long delayTime = (long) (Math.random() * 5000); // 随机生成0到5000毫秒的延迟时间
DelayedTask task = new DelayedTask(delayTime);
System.out.println(Thread.currentThread().getName() + " 生产: " + task);
queue.put(task);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
private final DelayQueue<DelayedTask> queue;
public Consumer(DelayQueue<DelayedTask> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
DelayedTask task = queue.take();
System.out.println(Thread.currentThread().getName() + " 消费: " + task);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
(5)SynchronousQueue
是 Java 并发包中的一个特殊的阻塞队列,它不存储任何元素。每个插入操作必须等待一个对应的移除操作,反之亦然。换句话说,SynchronousQueue 是一个直接移交(hand-off)队列,生产者线程必须等待消费者线程准备就绪才能进行元素的传递。
代码实现:
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
public class SynchronousQueueExample {
public static void main(String[] args) {
// 创建一个SynchronousQueue
SynchronousQueue<String> queue = new SynchronousQueue<>();
// 创建生产者线程
Thread producer = new Thread(new Producer(queue), "Producer");
// 创建消费者线程
Thread consumer = new Thread(new Consumer(queue), "Consumer");
// 启动线程
producer.start();
consumer.start();
}
static class Producer implements Runnable {
private final SynchronousQueue<String> queue;
public Producer(SynchronousQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
String message = "Message " + i;
System.out.println(Thread.currentThread().getName() + " 生产: " + message);
queue.put(message);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable {
private final SynchronousQueue<String> queue;
public Consumer(SynchronousQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
while (true) {
String message = queue.take();
System.out.println(Thread.currentThread().getName() + " 消费: " + message);
Thread.sleep((long) (Math.random() * 1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4.线程池(Executor Framework)
1.线程池(Executor Framework)
- 核心线程数 (corePoolSize):线程池中保持的核心线程数,即使这些线程处于空闲状态也不会被销毁。
- 最大线程数 (maximumPoolSize):线程池中允许的最大线程数。
- 线程空闲时间 (keepAliveTime):线程池中的空闲线程等待新任务的最长时间,超过这个时间后,空闲线程会被销毁。
- 工作队列 (workQueue):用于保存等待执行的任务的队列。
- 线程工厂 (threadFactory):用于创建新线程的工厂。
- 拒绝策略 (handler):当线程池无法接受新任务时(例如,线程池已达到最大线程数且工作队列已满),使用的处理策略。
代码实现:
// 创建一个线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60, // 线程空闲时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(10), // 工作队列
Executors.defaultThreadFactory(), // 线程工厂
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
具体流程:
1.检查当前线程数是否小于核心线程数,如果是,创建新的核心线程处理任务。如果不是,进入下一步。
2.检查工作队列是否已满:
如果未满,将任务放入工作队列。如果已满,进入下一步。
3.创建非核心线程
检查当前线程数是否小于最大线程数:
如果是,创建新的非核心线程处理任务。如果不是,进入下一步。
4.拒绝策略
根据拒绝策略处理任务(例如,CallerRunsPolicy 会将任务回退到调用者线程)
2.ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 是 ThreadPoolExecutor 的一个子类,专门用于执行定时任务和周期性任务。它提供了更丰富的调度功能。
代码实现:
import java.util.concurrent.*;
public class ScheduledThreadPoolExecutorExample {
public static void main(String[] args) {
// 创建一个ScheduledThreadPoolExecutor,核心线程数为2
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2);
// 延迟3秒执行任务
executor.schedule(() -> {
System.out.println("任务1执行了");
}, 3, TimeUnit.SECONDS);
// 延迟1秒后,每隔2秒执行一次任务
executor.scheduleAtFixedRate(() -> {
System.out.println("任务2执行了");
}, 1, 2, TimeUnit.SECONDS);
// 延迟1秒后,每次执行完后延迟2秒再次执行任务
executor.scheduleWithFixedDelay(() -> {
System.out.println("任务3执行了");
try {
Thread.sleep(1000); // 模拟任务执行时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 1, 2, TimeUnit.SECONDS);
// 关闭线程池
executor.shutdown();
}
}
3.Executors
快速创建线程池
代码实现:
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
5.锁(Locks)
1.ReentrantLock
与内置的 synchronized 关键字相比,ReentrantLock 提供了更多的灵活性和功能。同一个线程可以多次获取同一个锁,而不会导致死锁。每次获取锁时,锁的持有计数器会递增;每次释放锁时,锁的持有计数器会递减,当计数器为0时,锁被完全释放。
代码实现:
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count = 0;
private final ReentrantLock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
count--;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Counter counter = new Counter();
Runnable incrementTask = () -> {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
};
Runnable decrementTask = () -> {
for (int i = 0; i < 1000; i++) {
counter.decrement();
}
};
Thread t1 = new Thread(incrementTask);
Thread t2 = new Thread(decrementTask);
Thread t3 = new Thread(incrementTask);
Thread t4 = new Thread(decrementTask);
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终计数: " + counter.getCount());
}
}
2.ReentrantReadWriteLock
可重入的读写锁。它允许多个读线程同时访问共享资源,但在写线程访问时,不允许其他任何线程(包括读线程和写线程)访问。这种设计可以提高多读少写的场景下的并发性能。
代码实现:
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Cache {
private final Map<String, String> map = new HashMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
public String get(String key) {
readLock.lock();
try {
return map.get(key);
} finally {
readLock.unlock();
}
}
public void put(String key, String value) {
writeLock.lock();
try {
map.put(key, value);
} finally {
writeLock.unlock();
}
}
public void remove(String key) {
writeLock.lock();
try {
map.remove(key);
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
Cache cache = new Cache();
Runnable readTask = () -> {
for (int i = 0; i < 1000; i++) {
String value = cache.get("key");
if (value != null) {
System.out.println("读取到值: " + value);
}
}
};
Runnable writeTask = () -> {
for (int i = 0; i < 1000; i++) {
cache.put("key", "value" + i);
System.out.println("写入值: value" + i);
}
};
Thread t1 = new Thread(readTask);
Thread t2 = new Thread(writeTask);
Thread t3 = new Thread(readTask);
Thread t4 = new Thread(writeTask);
t1.start();
t2.start();
t3.start();
t4.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终缓存: " + cache.get("key"));
}
}
6.其他
1.ConcurrentHashMap
与传统的 HashMap 不同,ConcurrentHashMap 在多线程环境下提供了更高的并发性能,因为它内部使用了分段锁(Segment)机制来减少锁的竞争。从 Java 8 开始,ConcurrentHashMap 的实现进行了优化,使用了更细粒度的锁机制,进一步提高了并发性能。
代码实现:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 初始化数据
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(4);
// 提交读任务
for (int i = 0; i < 10; i++) {
executor.submit(() -> {
System.out.println("读取到值: " + map.get("A"));
});
}
// 提交写任务
for (int i = 0; i < 10; i++) {
final int index = i;
executor.submit(() -> {
map.put("A", map.get("A") + 1);
System.out.println("更新后的值: " + map.get("A"));
});
}
// 关闭线程池
executor.shutdown();
// 等待所有任务完成
while (!executor.isTerminated()) {
}
// 输出最终结果
System.out.println("最终结果: " + map);
}
}
2.CopyOnWriteArrayList 和 CopyOnWriteArraySet
它们通过在写操作时复制整个数组来实现线程安全,从而避免了在读操作时加锁的开销。这种设计特别适合于读多写少的场景。
代码实现:
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;
public class CopyOnWriteArrayListExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 添加元素
list.add("A");
list.add("B");
list.add("C");
// 创建线程池
Thread t1 = new Thread(() -> {
for (String item : list) {
System.out.println("读取到: " + item);
}
});
Thread t2 = new Thread(() -> {
list.add("D");
list.remove("B");
System.out.println("修改后: " + list);
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出最终结果
System.out.println("最终结果: " + list);
}
}
3.ThreadLocalRandom
一个随机数生成器,专门用于多线程环境,与 java.util.Random 相比,ThreadLocalRandom 在多线程环境下具有更好的性能,因为它为每个线程维护了一个独立的随机数生成器实例,从而避免了线程之间的竞争
代码实现:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
public class ThreadLocalRandomExample {
public static void main(String[] args) {
// 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(4);
// 提交任务
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
int randomInt = ThreadLocalRandom.current().nextInt(100);
long randomLong = ThreadLocalRandom.current().nextLong(1000);
double randomDouble = ThreadLocalRandom.current().nextDouble(1.0);
System.out.println("任务 " + taskId + " 生成的随机数: "
+ "int=" + randomInt + ", long=" + randomLong + ", double=" + randomDouble);
});
}
// 关闭线程池
executor.shutdown();
// 等待所有任务完成
while (!executor.isTerminated()) {
}
System.out.println("所有任务完成");
}
}