Debian Java多线程编程详解
小樊
38
2025-12-12 22:03:20
Debian Java多线程编程详解
一 环境准备与基础概念
- 在 Debian 上安装 OpenJDK 11(或系统默认 JDK),并验证版本:
- 安装命令:sudo apt update && sudo apt install openjdk-11-jdk
- 验证:java -version(应显示类似 openjdk version “11.0.x”)
- 多线程基础要点:
- 进程是资源分配单位,线程是 CPU 调度单位;同一进程的线程共享堆与方法区,但各自拥有栈和程序计数器。
- 线程生命周期包含:新建 NEW、可运行 RUNNABLE、阻塞 BLOCKED、等待 WAITING、超时等待 TIMED_WAITING、终止 TERMINATED。
- 多线程价值:提升吞吐量、增强响应性、更高效地利用多核与 I/O 等待时间。
二 创建线程与线程池
- 两种基础创建方式(示例):
- 继承 Thread:
- class MyThread extends Thread { public void run() { System.out.println("Thread running: " + Thread.currentThread().getName()); } }
- new MyThread().start();
- 实现 Runnable(更灵活,推荐):
- class MyRunnable implements Runnable { public void run() { … } }
- new Thread(new MyRunnable()).start();
- 使用线程池管理并发(推荐):
- ExecutorService executor = Executors.newFixedThreadPool(4);
- for (int i = 0; i < 10; i++) executor.submit(() -> doWork(i));
- 关闭:executor.shutdown(); executor.awaitTermination(30, TimeUnit.SECONDS);
- 常见线程池类型与适用场景:
- newFixedThreadPool(n):固定大小,适合CPU 密集型或稳定负载。
- newCachedThreadPool():弹性伸缩,适合短任务、突发流量。
- newSingleThreadExecutor():单线程顺序执行,适合串行任务。
- newScheduledThreadPool(n):定时/周期任务调度。
三 线程安全与同步机制
- 同步基石:
- synchronized:修饰方法或代码块,保证原子性、可见性、有序性;注意缩小临界区并避免嵌套锁顺序不当。
- ReentrantLock:提供更灵活的可中断、超时、公平锁等能力;务必在 finally 中 unlock。
- volatile:保证可见性、禁止指令重排序,不保证复合操作的原子性(如 i++)。
- 原子类:如 AtomicInteger,无锁实现计数器等简单共享变量的原子更新。
- 线程间协作与通信:
- 基于监视器的协作:wait/notify/notifyAll 必须在 synchronized 块内使用,用于条件等待与唤醒。
- 并发工具类:CountDownLatch(一次性门闩)、CyclicBarrier(循环栅栏)、Semaphore(限流)、Exchanger(成对交换)。
- 死锁预防要点:
- 按一致顺序获取多个锁;使用 tryLock(timeout);缩小锁粒度;避免持有锁时调用外部不可控代码。
四 有返回值任务与线程间协作实战
- Callable + Future(有返回值/可抛异常):
- ExecutorService exec = Executors.newSingleThreadExecutor();
- Future f = exec.submit(() -> { TimeUnit.SECONDS.sleep(1); return 42; });
- System.out.println("Result: " + f.get()); // 阻塞等待
- exec.shutdown();
- 典型协作模式模板(以 CountDownLatch 为例):
- 主线程创建 CountDownLatch(3);3 个工作线程各自完成任务后调用 countDown();主线程 await() 等待全部完成后再继续。
- 生产者-消费者(BlockingQueue 示例):
- 使用 BlockingQueue 作为安全缓冲区,生产者 put、消费者 take,队列满/空时自动阻塞,避免显式 wait/notify。
五 性能调优与常见问题
- 线程数量与任务类型:
- CPU 密集型:线程数 ≈ CPU 核心数(或 N+1);过多线程导致上下文切换开销上升。
- I/O 密集型:可适当增加线程数以覆盖 I/O 等待时间(结合压测调优)。
- 线程池参数化配置(ThreadPoolExecutor):
- 核心参数:corePoolSize、maximumPoolSize、keepAliveTime、workQueue、threadFactory、handler。
- 队列选择:有界队列(如 ArrayBlockingQueue)可防止资源耗尽;配合合理的拒绝策略(如 CallerRunsPolicy)。
- 可见性与内存模型:
- 理解 happens-before 规则;必要时使用 volatile 或同步手段建立先行关系,避免读到“过期”数据。
- 监控与排错:
- 使用 jstack 查看线程栈与死锁;为线程设置有意义的名称;在关键路径添加日志与异常处理(含未捕获异常处理器)。
- 工程化建议:
- 优先使用 并发容器(如 ConcurrentHashMap、BlockingQueue)与 原子类;避免直接 new Thread;统一通过 ExecutorService 提交任务。