java并发编程本质是基于juc包的协作模型,解决多线程安全高效共享状态与协同任务问题;实际开发应以executorservice为入口,配合atomicinteger、countdownlatch、concurrenthashmap、completablefuture等高级工具替代原始同步机制。

Java 并发编程不是“多线程写法集合”,而是围绕 java.util.concurrent(JUC)包构建的一套协作模型:它解决的是「多个线程如何安全、高效地共享状态并协同推进任务」,而不是单纯“让代码跑得更快”。
为什么直接 new Thread() + run() 容易出问题
手写 Thread 或实现 Runnable 是入门方式,但实际项目中几乎不用——因为缺少资源控制、异常传播、生命周期管理等能力。
- 线程创建/销毁开销大,频繁
new Thread().start()会迅速耗尽系统资源 -
run()中抛出的未捕获异常会静默消失,难以定位 - 无法统一管理线程执行顺序、超时、取消等行为
- 共享变量读写不加同步(如没用
volatile或synchronized)极易出现可见性或原子性问题
ExecutorService 是并发编程的实际入口
真正落地的 Java 并发始于 ExecutorService,它把“任务提交”和“线程调度”解耦。你提交的是 Runnable 或 Callable,它决定何时、由谁、用多少线程去执行。
- 优先使用
Executors.newFixedThreadPool(n)或Executors.newCachedThreadPool()—— 但注意:newCachedThreadPool在高负载下可能无限创建线程,生产环境建议用new ThreadPoolExecutor(...)显式配置 - 提交有返回值的任务用
submit(Callable<t>)</t>,返回Future<t></t>;调用get()会阻塞,记得设超时:future.get(3, TimeUnit.SECONDS) - 务必调用
shutdown()或shutdownNow(),否则 JVM 不会退出(线程池中的非守护线程会阻止进程终止)
共享状态必须用 JUC 工具而非原始同步
不要迷信 synchronized 块或 volatile 字段能覆盖所有场景。它们是基础原语,但易错且表达力弱;JUC 提供了更高层、更安全的抽象。
立即学习“Java免费学习笔记(深入)”;
- 计数类场景用
AtomicInteger而非synchronized块包裹++:前者无锁、更轻量,且保证原子性 - 需要等待某个条件成立?别手写
wait()/notify()—— 改用CountDownLatch(一次性)、CyclicBarrier(可重用)或Phaser(更灵活) - 缓存或配置类共享数据,用
ConcurrentHashMap替代HashMap + synchronized:它分段锁+CAS,吞吐高,且computeIfAbsent()等方法天然线程安全 - 避免在
ConcurrentHashMap上做复合操作(如“先 get 再 put”),仍需外部同步或改用compute()等原子方法
CompletableFuture 才是现代异步协作的核心
如果你还在用 Future.get() 阻塞等待结果,说明还没进入异步编程状态。CompletableFuture 把回调、组合、错误处理统一建模为链式操作。
-
supplyAsync(() -> heavyIO(), executor)指定线程池执行耗时任务,不阻塞主线程 - 用
thenApply()、thenCompose()、thenAccept()组装后续逻辑,失败走exceptionally()或handle() - 多个异步任务并行执行后聚合结果?
CompletableFuture.allOf()或CompletableFuture.anyOf(),但注意前者不返回结果,需手动 collect - 慎用
join()和get():它们会阻塞当前线程,破坏异步流水线;只在必要时(如测试、main 方法末尾)使用
真正难的不是写几个 Thread 或记住 synchronized 语法,而是判断该用 ReentrantLock 还是 StampedLock,该让任务排队还是拒绝,该用 CopyOnWriteArrayList 还是 ConcurrentLinkedQueue——这些选择背后是对数据访问模式、一致性要求、吞吐与延迟权衡的持续判断。









