当前位置: 首页 > news >正文

探索Java并发编程--从基础到高级实践技巧

Thread(线程)

线程 = 程序执行的最小单位(一个进程至少有一个线程)。线程内有自己的执行栈、程序计数器(PC),但与同进程内其他线程共享堆内存与进程资源

在java中,线程由java.lang.Thread表示,但我们通常不直接操作裸线程,而用更高层的并发工具(线程池、任务、并发集合等)

一、线程的生命周期与常见操作

状态:NEW、RUNNABLE、BLOCKED / WAITING / TIMED_WAITING、TERMINATED

  • NEW:对象创建后,未start()
  • RUNNABLE:可运行(包括实际运行或等待运行)
  • BLOCKED:等待获取对象监视器(synchronized)
  • WAITING:等待其他线程通知(Object.wait()、Thread.join()无超时)
  • TERMINATED:run方法返回或抛出异常结束

常用方法:

  • start():启动线程(不要直接调用run,会变成普通方法调用)
  • join():等待线程结束
  • sleep():当前线程休眠(会释放CPU,但不释放锁)
  • interrupt():中断线程(合作式,需要线程内检查isInterrupted()或捕获InterruptedException)
  • yield():礼让(建议少用,平台依赖)

二、创建线程

  1. 继承Thread
// 问题:单继承限制、职责不清(把任务和线程绑定)
class MyThread extends Thread {public void run() { /* 任务 */ }
}
new MyThread().start();
  1. 实现Runnable
// 好处:解耦任务和线程、可复用
Runnable task = () -> { /* 任务 */ };
new Thread(task).start();
  1. 实现Callable + Future(用于返回值 / 异常)
// 支持返回值和抛异常
Callable<Integer> c = () -> 1+2;
Future<Integer> f = executor.submit(c);
Integer result = f.get(); // 阻塞取结果
  1. 使用线程池(ExecutorService / ThreadPoolExecutor)
ExecutorService pool = Executors.newFixedThreadPool(5);
pool.submit(() -> { /* 任务 */ });
pool.shutdown();
// 不要滥用Executor.*生成的未定制池(可能使用无界队列或者不合适的场景)一般直接构造ThreadPoolExecutor并调参
  1. ForkJoinPool(分治、并行流)
  • 适合CPU密集型、可分解任务(RecursiveTask)。采用工作窃取(work-stealing)
  1. CompletableFuture(异步组合)
  • 异步流式编程supplyAsync、链式 thenApply、异常处理 exceptionally,能把异步任务组合成复杂流程。
  1. 虚拟线程(Project Loom —— 概念)
  • 新一代思想:大量“轻量级线程”由 JVM 管理,降低线程/请求的成本,能用同步编程模型写大并发程序。
  • (提示:具体语法/可用性随 JDK 版本变化,写生产代码前确认 JDK 支持情况。)

三、同步与内存可见性

并发核心问题是:共享可变状态会导致竞态、可见性问题

  1. synchronized(内置锁)

    • 监视器(monitor):synchronized修饰方法或代码块
    • 可重入(同一线程可重复获得同一把锁)
    • wait() / notify() / notifyAll()在持锁状态下使用,用于线程间协作
    // 特点:保证同一时刻只有一个线程能执行临界区代码,并且进入 / 退出时会触发内存可见性更新/*单例模式(懒汉式加锁)
    */
    public class Singleton {private static Singleton instance;public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
    }/*多线程安全更新共享资源
    */
    public class Counter {private int count = 0;public synchronized void increment() {count++;}public synchronized int getCount() {return count;}
    }/*保证集合安全(eg:ArrayList在多线程下不安全,可用Collections.synchronizedList包装)
    */
    
  2. volatile

    • 保证可见性(写入一个volatile变量后,后续读能看到最新值)和禁止指令重排序(对单个变量)
    • 不能替代锁来保证复合操作的原子性(比如count++不是原子性)
    // 特点:让一个线程修改的变量能立即被其他线程看到;禁止指令重排序。
    //     适合 状态标志、开关类变量
    /*线程停止标志
    */
    class Task implements Runnable {private volatile boolean running = true;public void run() {while (running) {// do work...}}public void stop() {running = false; // 立刻被其他线程看到}
    }
    /*配置热更新一个后台线程定时刷新配置,把值写入volatile变量,业务线程能马上读到新值
    */// 注意:下面这种情况要用synchronized或AtomicInteger
    
  3. Lock(java.util.concurrent.locks)

    • ReentrantLock:比synchronized更灵活(可中断获取锁、可轮询、可超时),支持Condition(类似多个wait / nottify集合)
    • ReadWriteLock:读写分离锁,读多写少场景有利
    // 显示锁,比synchronized更灵活,可定时、可中断、支持多个条件队列
    /*尝试获取锁(避免死等)
    */
    ReentrantLock lock = new ReentrantLock();
    if (lock.tryLock(1, TimeUnit.SECONDS)) {try {// 临界区} finally {lock.unlock();}
    } else {// 获取锁失败,执行降级逻辑
    }/* 读写分离(适合读多写少)
    */
    ReadWriteLock rwLock = new ReentrantReadWriteLock();
    Lock r = rwLock.readLock();
    Lock w = rwLock.writeLock();
    
  4. 原子类(AtomicInteger / Long / Reference)

    • 基于CAS(无锁算法),用于计数等简单场景。注意ABA问题(可用AtomicStampedReference)
    // 基于CAS实现的无锁并发,常用于计数器、序列号
    /*高性能计数器
    */
    private AtomicInteger count = new AtomicInteger();
    public void increment() {count.incrementAndGet();
    }/*并发限流 / 统计QPS、在线人数统计,避免用synchronized降低性能
    */
    
  5. 内存模型(JMM)要点

    • 主内存 + 工作内存(线程本地缓存),写到主内存后其他线程可见。volatile / 锁会产生内存屏障,保证可见性与有序性

四、常用并发工具(java.util.concurrent)

  • 线程池:ThreadoolExecutor(核心、最大线程数、队列、饱和策略)
  • 阻塞队列:ArrayBlockingQueue,LinkBlockingQueue,PriorityBlockQueue(常用于生产者-消费者)
  • 同步辅助类:CountDownLatch, CyclicBarrier, Semaphore, Phaser, Exchanger
  • 并发集合:ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue
  • ForkJoinPool(并行任务)
  • BlockingQueue + ThreadPool:典型生产者-消费者模式
  • FutureTask:可作为Runnable也可获取结果,常用于把Callable封装成任务

五、线程安全问题与常见陷阱

  • 竞态条件(race condition):并发修改同一状态导致错误结果
  • 死锁(deadlock):两个或多个线程互相持有对方需要的锁。四要素:互斥、持有并等待、不可剥夺、循环等待
  • 活锁(livelock):线程不断执行但无法取得进展(一直让步)
  • 饥饿(starvation):某线程长期无法获得CPU或锁资源
  • 优先级反转(priority inversion):低优先级线程持锁导致高优先级线程等待
  • 内存泄露(ThreadLocal):线程池中使用ThreadLocal若不remove(),会造成对象无法回收(尤其在容器应用中)

排查工具:jstack(线程dump)、jvisualvm、jconsole、应用日志、线程名 / ID打点、Flight Recorder。线程dump是定位死锁 / 阻塞的利器

六、守护线程(Daemon)vs 用户线程(User)

  • 用户线程:只要存在任意用户线程,JVM不会退出
  • 守护线程:JVM在所有用户线程结束后会退出,即使守护线程还在跑

文章转载自:

http://LzoxZYq8.mtgkq.cn
http://t9WQBmXp.mtgkq.cn
http://OVDynjlY.mtgkq.cn
http://OBoKx2qj.mtgkq.cn
http://GU5sgwfJ.mtgkq.cn
http://iXS8cVkV.mtgkq.cn
http://gXW2QNhb.mtgkq.cn
http://g7Wl09ou.mtgkq.cn
http://hTAtijDV.mtgkq.cn
http://B0HUUzig.mtgkq.cn
http://nGS0Jt86.mtgkq.cn
http://XhBjtgWs.mtgkq.cn
http://zxUcbUWS.mtgkq.cn
http://ZHSmdb5G.mtgkq.cn
http://0aJtVtiC.mtgkq.cn
http://f6gTDi1Y.mtgkq.cn
http://p2cnYPrq.mtgkq.cn
http://63IxeLeS.mtgkq.cn
http://K02OlAxQ.mtgkq.cn
http://ND4WjvWe.mtgkq.cn
http://c8k2fvD5.mtgkq.cn
http://HV36wb3Y.mtgkq.cn
http://J1VIhv9b.mtgkq.cn
http://8nfDquGB.mtgkq.cn
http://B4ejWC4V.mtgkq.cn
http://ULdSox7Z.mtgkq.cn
http://9VpSOdT6.mtgkq.cn
http://9nwtJrQN.mtgkq.cn
http://5jxzg3g1.mtgkq.cn
http://dMWtExOS.mtgkq.cn
http://www.dtcms.com/a/374869.html

相关文章:

  • Made in Green环保健康产品认证怎么做?
  • yum list 和 repoquery的区别
  • 解决HTML/JS开发中的常见问题与实用资源
  • Angular 面试题及详细答案
  • AI与AR融合:重塑石化与能源巡检的未来
  • 增强现实光学系统_FDTD_zemax_speos_学习(1)
  • 开学季干货——知识梳理与经验分享
  • Alex Codes团队并入OpenAI Codex:苹果生态或迎来AI编程新篇章
  • The learning process of Decision Tree Model|决策树模型学习过程
  • 六、与学习相关的技巧(下)
  • 《低功耗音频:重塑听觉体验与物联网边界的蓝牙革命》
  • 20250909的学习笔记
  • 金融量化指标--5Sortino索提诺比率
  • 消息三剑客华山论剑:Kafka vs RabbitMQ vs RocketMQ
  • 均值/方差/标注查介绍
  • 深入解析Guava RateLimiter限流机制
  • 开发中使用——鸿蒙子页面跳转到指定Tab页面
  • HarmonyOS实现快递APP自动识别地址
  • AJAX入门-URL
  • 【C++】18. 红⿊树实现
  • 基于Java Spring Boot的云原生TodoList Demo 项目,验证云原生核心特性
  • 记录一次rk3568硬解码时cpu占用率高的问题
  • Electron 跨平台兼容性:处理 OS 差异
  • Docker 学习笔记(五):网络与存储核心原理及实战应用
  • Who Wants To Be King: 1靶场渗透
  • PgSQL监控死元组和自动清理状态的SQL语句执行报错ERROR: division by zero原因分析和解决方法
  • 深入理解 MyBatis-Plus 的 QueryWrapper:动态 SQL 构建的利器
  • 文件的相关概念
  • 注解参数校验
  • AI 测试平台新功能揭秘:自动化测试用例运行的奥秘