首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java 并发编程实战详解:线程、线程池与锁机制

Java 并发编程实战详解:线程、线程池与锁机制

原创
作者头像
用户11690571
发布2025-06-06 21:37:30
发布2025-06-06 21:37:30
4210
举报

一、引言:并发编程为何如此重要?

现代计算机大多是多核处理器,利用并发编程能提升程序吞吐量与响应速度。Java 提供了非常完善的并发工具集,涵盖从基础线程到高级并发类库,帮助开发者构建高性能、线程安全的程序。


二、Java 并发编程体系图解

代码语言:javascript
复制
php-template复制编辑java.lang.Thread
│
├── Runnable
├── Callable<V>
├── Future<V>
│
└── java.util.concurrent.*
      ├── Executor / ExecutorService
      ├── ThreadPoolExecutor
      ├── ForkJoinPool
      ├── CountDownLatch / CyclicBarrier
      ├── Lock / ReentrantLock
      └── Concurrent Collections

三、基础线程机制

3.1 继承 Thread

代码语言:javascript
复制
java复制编辑class MyThread extends Thread {
    public void run() {
        System.out.println("线程执行:" + Thread.currentThread().getName());
    }
}
代码语言:javascript
复制
java复制编辑MyThread t = new MyThread();
t.start();

3.2 实现 Runnable 接口

代码语言:javascript
复制
java复制编辑Runnable task = () -> System.out.println("使用Runnable执行线程!");
new Thread(task).start();

对比分析:

方式

优点

缺点

继承 Thread

编写简单

不能继承其他类

实现 Runnable

更灵活,可共享资源

无法返回结果


四、线程池的使用与原理

线程池(ThreadPoolExecutor)能重用线程资源,避免频繁创建销毁线程。

4.1 快速使用线程池

代码语言:javascript
复制
java复制编辑ExecutorService executor = Executors.newFixedThreadPool(4);

executor.submit(() -> {
    System.out.println("线程池任务执行中");
});
executor.shutdown();

4.2 线程池核心参数详解(图示)

代码语言:javascript
复制
java复制编辑ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, // 核心线程数
    maximumPoolSize, // 最大线程数
    keepAliveTime, // 非核心线程闲置超时
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(), // 队列
    new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);

线程池执行流程图:

代码语言:javascript
复制
lua复制编辑          +-----------+       +-------------+
请求任务 →| 核心线程 | ----> | 任务队列    |
          +-----------+       +-------------+
                ↓                ↓
         非核心线程创建    超出 → 拒绝策略执行

五、线程通信与同步机制

5.1 synchronized 使用场景

代码语言:javascript
复制
java复制编辑public synchronized void increment() {
    count++;
}

或代码块:

代码语言:javascript
复制
java复制编辑synchronized (lock) {
    count++;
}

5.2 Lock 可重入锁

代码语言:javascript
复制
java复制编辑Lock lock = new ReentrantLock();

lock.lock();
try {
    // 临界区
} finally {
    lock.unlock();
}

特性

synchronized

ReentrantLock

可重入

公平锁支持

可中断锁获取

条件变量(等待/通知)


六、Callable 与 Future 异步编程

代码语言:javascript
复制
java复制编辑ExecutorService pool = Executors.newSingleThreadExecutor();

Callable<String> task = () -> {
    Thread.sleep(1000);
    return "任务完成";
};

Future<String> result = pool.submit(task);
System.out.println(result.get());  // 阻塞等待返回结果

七、常用并发工具类

工具类

说明

CountDownLatch

倒计时器,等待所有线程完成

CyclicBarrier

循环栅栏,所有线程到达后统一执行

Semaphore

信号量控制并发量

BlockingQueue

支持线程安全的队列操作

ConcurrentHashMap

高性能线程安全的哈希表实现

示例:CountDownLatch

代码语言:javascript
复制
java复制编辑CountDownLatch latch = new CountDownLatch(3);

for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        System.out.println("子线程执行完成");
        latch.countDown();
    }).start();
}

latch.await();  // 等待所有子线程完成
System.out.println("主线程继续执行");

八、线程安全集合类

类名

特点

CopyOnWriteArrayList

适合读多写少场景

ConcurrentHashMap

分段锁,读写并发效率高

ConcurrentLinkedQueue

非阻塞队列,适合并发访问


九、多线程常见问题与陷阱

问题

原因说明

死锁(Deadlock)

多线程互相等待资源,形成闭环

资源竞争(Race Condition)

多线程同时修改同一变量,结果不可预测

可见性问题

一个线程修改变量,其他线程不可见

线程不安全的单例模式

多线程创建多个实例

解决策略

  • 使用 volatile 保证变量可见性
  • 使用 synchronizedLock
  • 避免多个锁交叉调用造成死锁
  • 使用线程安全类库(如 AtomicInteger

十、JUC 高级组件与原子类

原子类

功能

AtomicInteger

原子递增

AtomicReference

原子更新对象引用

LongAdder / DoubleAdder

高并发下减少伪共享,计数更高效

示例:AtomicInteger

代码语言:javascript
复制
java复制编辑AtomicInteger counter = new AtomicInteger(0);

counter.incrementAndGet();  // 原子递增

十一、最佳实践建议

场景

推荐方式

创建短任务线程

使用线程池(Executor)

大量读操作共享数据

使用 CopyOnWriteArrayList

高并发计数器

使用 LongAdder / AtomicInteger

控制最大并发访问

使用 Semaphore

等待多个线程完成任务

使用 CountDownLatch


十二、可视化线程调试工具

工具

功能

jconsole

监控线程状态、内存、GC

jstack

打印线程堆栈,排查死锁

VisualVM

图形化监控工具,查看线程运行状况

Arthas

实时诊断 Java 应用,支持热加载


十三、面试高频问题速查表

问题

要点提炼

Thread 与 Runnable 区别

继承 vs 接口,灵活性 vs 继承限制

synchronized 和 Lock 的区别

可中断、公平锁、性能调优

什么是死锁?怎么避免?

资源占用 + 顺序锁定,避免循环依赖

线程池核心参数有哪些?

corePoolSize、maxPoolSize、queue 等

ConcurrentHashMap 是如何保证并发安全的?

分段锁(JDK7),CAS + 链表(JDK8)


十四、总结

Java 并发编程的核心是:

  • 理解线程的本质和生命周期
  • 正确选择同步方式(锁、工具类)
  • 灵活应用线程池和原子类
  • 规避并发编程陷阱(如死锁、可见性问题)

想要写出高性能并发程序,不仅要掌握语法,更要理解原理与设计哲学。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、引言:并发编程为何如此重要?
  • 二、Java 并发编程体系图解
  • 三、基础线程机制
    • 3.1 继承 Thread
    • 3.2 实现 Runnable 接口
    • 对比分析:
  • 四、线程池的使用与原理
    • 4.1 快速使用线程池
    • 4.2 线程池核心参数详解(图示)
  • 五、线程通信与同步机制
    • 5.1 synchronized 使用场景
    • 5.2 Lock 可重入锁
  • 六、Callable 与 Future 异步编程
  • 七、常用并发工具类
    • 示例:CountDownLatch
  • 八、线程安全集合类
  • 九、多线程常见问题与陷阱
    • 解决策略
  • 十、JUC 高级组件与原子类
    • 示例:AtomicInteger
  • 十一、最佳实践建议
  • 十二、可视化线程调试工具
  • 十三、面试高频问题速查表
  • 十四、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档