JavaSE-10-并发编程(11个案例)

JavaSE-10-并发编程(11个案例)

本文将通过多个高并发场景下的实战案例,深入学习理解线程池、线程协作、线程安全集合、锁机制、ThreadLocal 等并发工具的综合运用,进一步巩固并发编程技能,提升实战能力。


1. 生产者-消费者

1.1 场景描述

生产者-消费者模型是并发编程中最经典的模型之一,用于解耦数据的生产与消费,适用于任务队列、消息队列等场景。

1.2 实现方式

复制代码
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ProducerConsumer { private final BlockingQueue<Integer> queue = new LinkedBlockingQueue <>( 10 ); class Producer implements Runnable { @Override public void run () { try { for ( int i = 0 ; i < 100 ; i++) { queue.put(i); System.out.println( "Produced: " + i); Thread.sleep( 50 ); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } class Consumer implements Runnable { @Override public void run () { try { while ( true ) { Integer value = queue.take(); System.out.println( "Consumed: " + value); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } public static void main (String[] args) { ProducerConsumer pc = new ProducerConsumer (); new Thread (pc. new Producer ()).start(); new Thread (pc. new Consumer ()).start(); } }

1.3 关键点分析

组件 作用
BlockingQueue 提供线程安全的队列操作(put/take)
LinkedBlockingQueue 支持无界队列,适合高吞吐场景
Thread.sleep() 模拟生产/消费耗时
InterruptedException 捕获中断信号,保证线程安全退出

1.4 优化建议

  • 使用线程池管理生产者/消费者线程;
  • 使用 ArrayBlockingQueue 限制队列大小,防止内存溢出;
  • 使用 SynchronousQueue 实现直接传递任务;
  • 使用 DelayQueue 实现延迟消费逻辑。

2. 异步任务处理

2.1 场景描述

在高并发系统中,经常需要并行执行多个任务并等待结果,如并发调用多个接口、批量处理任务等。可以使用线程池 + Future 实现异步处理。

2.2 实现方式

复制代码
import java.util.concurrent.*; public class FutureTaskExample { public static void main (String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newFixedThreadPool( 4 ); Future<Integer> future1 = executor.submit(() -> { Thread.sleep( 1000 ); return 100 ; }); Future<Integer> future2 = executor.submit(() -> { Thread.sleep( 1500 ); return 200 ; }); System.out.println( "Result1: " + future1.get()); System.out.println( "Result2: " + future2.get()); executor.shutdown(); } }

2.3 关键点分析

组件 作用
ExecutorService 线程池管理任务执行
Future 异步获取任务结果
get() 阻塞等待任务完成
submit(Callable) 提交带返回值的任务
shutdown() 平滑关闭线程池

2.4 优化建议

  • 使用 invokeAll() 批量提交任务;
  • 使用 CompletableFuture 替代 Future,支持链式调用;
  • 使用 Future.get(timeout, unit) 避免任务长时间阻塞;
  • 使用 ThreadPoolTaskExecutor(Spring)进行更精细控制;

3. 自定义阻塞队列

3.1 场景描述

当需要实现一个自定义阻塞队列 (如用于任务调度、事件驱动系统),可以使用 ReentrantLockCondition 实现。

3.2 实现方式

复制代码
import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class CustomBlockingQueue <T> { private final Queue<T> queue = new LinkedList <>(); private final int capacity; private final Lock lock = new ReentrantLock (); private final Condition notEmpty = lock.newCondition(); private final Condition notFull = lock.newCondition(); public CustomBlockingQueue ( int capacity) { this .capacity = capacity; } public void put (T item) throws InterruptedException { lock.lock(); try { while (queue.size() == capacity) { notFull.await(); } queue.offer(item); notEmpty.signal(); } finally { lock.unlock(); } } public T take () throws InterruptedException { lock.lock(); try { while (queue.isEmpty()) { notEmpty.await(); } T item = queue.poll(); notFull.signal(); return item; } finally { lock.unlock(); } } public static void main (String[] args) { CustomBlockingQueue<Integer> queue = new CustomBlockingQueue <>( 5 ); new Thread (() -> { try { for ( int i = 0 ; i < 10 ; i++) { queue.put(i); System.out.println( "Put: " + i); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); new Thread (() -> { try { for ( int i = 0 ; i < 10 ; i++) { System.out.println( "Take: " + queue.take()); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); } }

3.3 关键点分析

组件 作用
ReentrantLock 提供可中断、公平锁等高级锁控制
Condition 替代传统的 wait/notify ,实现更清晰的线程等待/唤醒机制
await() / signal() 等待和唤醒线程
while 检查条件 避免虚假唤醒

3.4 优化建议

  • 使用 ReentrantLock 的公平锁模式控制线程调度顺序;
  • 使用 tryLock() 避免死锁;
  • 使用 Condition 替代 synchronizedwait/notify,提高可读性和灵活性;
  • 可扩展为 ArrayBlockingQueueLinkedBlockingQueue 的简化版实现;

4. 多线程下载文件并分块合并

4.1 场景描述

在下载大文件时,使用多线程分段下载,并最终合并文件片段,提高下载效率。

4.2 实现思路

    1. 计算文件总大小
    1. 根据线程数划分下载区间
    1. 使用线程池并发下载各段
    1. 合并所有片段
    1. 使用 CountDownLatch控制合并时机

4.3 示例代码

复制代码
import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.*; public class MultiThreadDownloader { private static final int THREAD_COUNT = 4 ; public static void main (String[] args) throws Exception { String urlStr = "http://example.com/largefile.zip" ; URL url = new URL (urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); int fileSize = conn.getContentLength(); int partSize = fileSize / THREAD_COUNT; CountDownLatch latch = new CountDownLatch (THREAD_COUNT); ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); for ( int i = 0 ; i < THREAD_COUNT; i++) { final int index = i; final int start = i * partSize; final int end = (i == THREAD_COUNT - 1 ) ? fileSize : (i + 1 ) * partSize - 1 ; executor.submit(() -> { try { downloadPart(urlStr, start, end, index); latch.countDown(); } catch (Exception e) { e.printStackTrace(); } }); } latch.await(); executor.shutdown(); mergeFiles(THREAD_COUNT); } private static void downloadPart (String urlStr, int start, int end, int index) throws Exception { HttpURLConnection conn = (HttpURLConnection) new URL (urlStr).openConnection(); conn.setRequestProperty( "Range" , "bytes=" + start + "-" + end); try ( InputStream in = conn.getInputStream(); FileOutputStream out = new FileOutputStream ( "part_" + index)) { byte [] buffer = new byte [ 4096 ]; int bytesRead; while ((bytesRead = in.read(buffer)) != - 1 ) { out.write(buffer, 0 , bytesRead); } } } private static void mergeFiles ( int partCount) throws IOException { try ( FileOutputStream fos = new FileOutputStream ( "final_file" )) { for ( int i = 0 ; i < partCount; i++) { try ( FileInputStream fis = new FileInputStream ( "part_" + i)) { byte [] buffer = new byte [ 4096 ]; int bytesRead; while ((bytesRead = fis.read(buffer)) != - 1 ) { fos.write(buffer, 0 , bytesRead); } } } } } }

4.3 关键点分析

组件 作用
CountDownLatch 控制所有线程完成后再合并
ExecutorService 管理并发下载线程
HttpURLConnection 分段下载
RandomAccessFile 可选:支持写入指定位置,避免合并

4.4 优化建议

  • 使用 RandomAccessFile 直接写入文件偏移位置,避免合并;
  • 使用 CompletableFuture 实现异步下载和合并;
  • 使用 FileChannel + MappedByteBuffer 提升 IO 性能;
  • 增加断点续传逻辑(记录下载偏移量);

5. 实现请求上下文隔离

5.1 场景描述

在 Web 应用中,每个请求需要维护请求上下文信息 (如用户信息、日志上下文、事务信息等),使用 ThreadLocal 可以实现线程级别的数据隔离。

5.2 实现方式

复制代码
public class RequestContext { private static final ThreadLocal<String> currentUser = new ThreadLocal <>(); public static void setCurrentUser (String user) { currentUser.set(user); } public static String getCurrentUser () { return currentUser.get(); } public static void clear () { currentUser.remove(); } } // 模拟请求处理 public class RequestHandler implements Runnable { private final String user; public RequestHandler (String user) { this .user = user; } @Override public void run () { try { RequestContext.setCurrentUser(user); System.out.println( "Processing request for: " + RequestContext.getCurrentUser()); // 模拟业务逻辑 Thread.sleep( 1000 ); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { RequestContext.clear(); } } public static void main (String[] args) { ExecutorService pool = Executors.newFixedThreadPool( 4 ); pool.submit( new RequestHandler ( "user1" )); pool.submit( new RequestHandler ( "user2" )); pool.shutdown(); } }

5.3 关键点分析

组件 作用
ThreadLocal 每个线程拥有独立副本,避免共享
remove() 避免内存泄漏(线程池中线程复用)
线程池场景 确保 remove() 在任务结束时调用

5.4 优化建议

  • 使用 InheritableThreadLocal 支持父子线程传递;
  • 使用 TransmittableThreadLocal(阿里开源)解决线程池上下文传递问题;
  • try-finally 中调用 remove(),防止内存泄漏;
  • 用于日志追踪(如 MDC)、用户上下文、事务管理等场景;

6. 支持并发的 LRU 缓存

  • 使用 ConcurrentHashMap 存储缓存;

  • 使用 ReentrantLock 控制并发;

  • 支持自动淘汰最近最少使用的元素。

    import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; public class LRUCache <K, V> { private final int maxSize; private final Map<K, V> cache = new ConcurrentHashMap <>(); private final Map<K, AtomicInteger> usageCount = new ConcurrentHashMap <>(); private final ReentrantLock lock = new ReentrantLock (); public LRUCache ( int maxSize) { this .maxSize = maxSize; } public V get (K key) { lock.lock(); try { usageCount.computeIfPresent(key, (k, v) -> new AtomicInteger (v.incrementAndGet())); return cache.get(key); } finally { lock.unlock(); } } public void put (K key, V value) { lock.lock(); try { if (cache.size() >= maxSize) { evict(); } cache.put(key, value); usageCount.put(key, new AtomicInteger ( 1 )); } finally { lock.unlock(); } } private void evict () { K lruKey = usageCount.entrySet().stream() .min(Map.Entry.comparingByValue((a, b) -> Integer.compare(a.get(), b.get()))) .map(Map.Entry::getKey) .orElse( null ); if (lruKey != null ) { cache.remove(lruKey); usageCount.remove(lruKey); } } }


7. 支持重试机制的异步下载器

  • 使用 CompletableFuture 实现异步下载;

  • 下载失败时自动重试;

  • 支持设置最大重试次数。

    import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; public class RetryableDownloader { private static final int MAX_RETRY = 3 ; public static void main (String[] args) { String url = "http://example.com/largefile.zip" ; String output = "downloaded_file" ; CompletableFuture<Void> future = CompletableFuture.runAsync(() -> { AtomicInteger retry = new AtomicInteger ( 0 ); while (retry.get() < MAX_RETRY) { try { downloadFile(url, output); System.out.println( "Download completed." ); return ; } catch (IOException e) { System.out.println( "Download failed, retrying..." ); retry.incrementAndGet(); } } System.out.println( "Download failed after " + MAX_RETRY + " retries." ); }); future.exceptionally(ex -> { System.out.println( "Error: " + ex.getMessage()); return null ; }); future.join(); } private static void downloadFile (String url, String output) throws IOException { // 模拟下载失败 if (Math.random() < 0.5 ) { throw new IOException ( "Simulated network error" ); } try ( InputStream in = new URL (url).openStream(); OutputStream out = new FileOutputStream (output)) { byte [] buffer = new byte [ 4096 ]; int bytesRead; while ((bytesRead = in.read(buffer)) != - 1 ) { out.write(buffer, 0 , bytesRead); } } } }


8. 线程安全的计数器

  • 使用 LongAdderReentrantLock 实现两个版本的线程安全计数器;

  • 对比性能差异。

    import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.ReentrantLock; public class CounterComparison { private static final int THREAD_COUNT = 100 ; private static final int LOOP_COUNT = 100000 ; public static void main (String[] args) throws InterruptedException { // 使用 LongAdder LongAdder longAdder = new LongAdder (); ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); long start = System.currentTimeMillis(); for ( int i = 0 ; i < THREAD_COUNT; i++) { executor.submit(() -> { for ( int j = 0 ; j < LOOP_COUNT; j++) { longAdder.increment(); } }); } executor.shutdown(); executor.awaitTermination( 1 , TimeUnit.MINUTES); System.out.println( "LongAdder result: " + longAdder.sum()); System.out.println( "LongAdder time: " + (System.currentTimeMillis() - start) + " ms" ); // 使用 ReentrantLock ReentrantLock lock = new ReentrantLock (); long counter = 0 ; ExecutorService executor2 = Executors.newFixedThreadPool(THREAD_COUNT); long start2 = System.currentTimeMillis(); for ( int i = 0 ; i < THREAD_COUNT; i++) { executor2.submit(() -> { for ( int j = 0 ; j < LOOP_COUNT; j++) { lock.lock(); try { counter++; } finally { lock.unlock(); } } }); } executor2.shutdown(); executor2.awaitTermination( 1 , TimeUnit.MINUTES); System.out.println( "ReentrantLock result: " + counter); System.out.println( "ReentrantLock time: " + (System.currentTimeMillis() - start2) + " ms" ); } }


9. 线程安全的配置中心

  • 使用 CopyOnWriteArrayList 存储配置;

  • 支持并发读取;

  • 支持动态更新配置。

    import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class ThreadSafeConfigCenter { private final List<String> configs = new CopyOnWriteArrayList <>(); public void addConfig (String config) { configs.add(config); } public void updateConfig ( int index, String newConfig) { configs.set(index, newConfig); } public void printAllConfigs () { for (String config : configs) { System.out.println(config); } } public static void main (String[] args) { ThreadSafeConfigCenter center = new ThreadSafeConfigCenter (); ExecutorService pool = Executors.newFixedThreadPool( 4 ); for ( int i = 0 ; i < 100 ; i++) { int finalI = i; pool.submit(() -> center.addConfig( "Config-" + finalI)); } for ( int i = 0 ; i < 10 ; i++) { int index = i % 100 ; int finalI = i; pool.submit(() -> center.updateConfig(index, "Updated-Config-" + finalI)); } pool.shutdown(); try { pool.awaitTermination( 1 , TimeUnit.MINUTES); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } center.printAllConfigs(); } }


10. 请求追踪系统

  • 使用 ThreadLocal 记录请求 ID;

  • 使用 MDC 记录日志上下文;

  • 支持日志追踪。

    import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class RequestTracer { private static final ThreadLocal<String> requestId = new ThreadLocal <>(); private static final Logger logger = LoggerFactory.getLogger(RequestTracer.class); public static void main (String[] args) { ExecutorService pool = Executors.newFixedThreadPool( 4 ); for ( int i = 0 ; i < 10 ; i++) { String id = "req-" + i; pool.submit(() -> { requestId.set(id); MDC.put( "requestId" , id); logger.info( "Processing request..." ); requestId.remove(); MDC.clear(); }); } pool.shutdown(); } }


11. 线程安全的定时任务调度器

  • 使用 ScheduledExecutorService 实现定时任务;

  • 支持任务取消;

  • 支持任务重试机制。

    import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; public class SafeScheduledTask { public static void main (String[] args) { ScheduledExecutorService scheduler = Executors.newScheduledThreadPool( 2 ); ScheduledFuture<?> future = scheduler.scheduleAtFixedRate(() -> { try { System.out.println( "Executing task..." ); } catch (Exception e) { System.err.println( "Task failed: " + e.getMessage()); } }, 0 , 1 , TimeUnit.SECONDS); // 5秒后取消任务 Executors.newSingleThreadScheduledExecutor().schedule(future::cancel, 5 , TimeUnit.SECONDS); } }


12. 总结

案例 核心知识点 适用场景
生产者-消费者 BlockingQueue 、线程通信 任务队列、消息队列
Future 异步处理 ExecutorService 、 Future 、 Callable 并行计算、异步任务
自定义阻塞队列 ReentrantLock 、 Condition 自定义任务调度、事件驱动
多线程下载 HttpURLConnection 、 CountDownLatch 大文件下载、IO 并发
请求上下文隔离 ThreadLocal 、线程安全 Web 请求处理、日志追踪
LRU 缓存 ConcurrentHashMap 、 ReentrantLock 缓存管理、资源缓存
异步下载器 CompletableFuture 、重试机制 并行下载、失败重试
线程安全计数器 LongAdder 、 ReentrantLock 高并发计数器
配置中心 CopyOnWriteArrayList 、线程安全 读多写少的配置管理
请求追踪系统 ThreadLocal 、MDC 日志追踪、请求上下文隔离
定时任务调度器 ScheduledExecutorService 、 Future 定时采集、心跳检测
相关推荐
ashen♂1 小时前
OpenClaw Windows本机安装
ai·openclaw
石山代码1 小时前
java前景
java·开发语言
10岁的博客1 小时前
C++ 进制转换:通用 a 进制转 b 进制(2-36进制)题解
开发语言·c++
Cthy_hy1 小时前
树状数组(BIT)进阶:差分优化实现区间修改、区间查询
数据结构·python·算法
希望永不加班1 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html
码界筑梦坊1 小时前
133-基于Python的全球城市生活成本数据可视化分析系统
开发语言·python·信息可视化·django·毕业设计·生活
Evand J1 小时前
【MATLAB控制例程】(9)多无人机编队协同控制与三维轨迹规划仿真,附下载链接
开发语言·分布式·matlab·无人机·控制
小二·2 小时前
LangGraph 多智能体实战:从零搭建 Multi-Agent 协作系统
java·开发语言·数据库