温馨提示×

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 提交任务。

0