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

【026】线程状态与 synchronized 基础

写业务代码时,你可能写过这样的代码:

// 多线程并发修改共享数据privateintcount=0;publicvoidincrement(){count++;// 非原子操作,有并发问题}

这就是典型的线程安全问题。多个线程同时修改同一个数据,导致结果不可预期。

理解线程和 synchronized,能帮你:

  • 写出线程安全的代码
  • 理解 Java 并发问题的根因
  • 为学习更高级的并发工具打基础

下面我按「线程状态 → 线程创建 → synchronized 基础 → 锁升级」的顺序往下聊。


1. 线程的六种状态 🔄

1.1 线程状态概览

Java 中线程有六种状态

// Thread.State 枚举publicenumState{NEW,// 新建RUNNABLE,// 可运行BLOCKED,// 阻塞WAITING,// 等待TIMED_WAITING,// 超时等待TERMINATED// 终止}

1.2 状态转换图

线程状态转换: │ NEW → START │ RUNNABLE ←→ BLOCKED(synchronized 锁竞争) │ RUNNABLE ←→ WAITING(Object.wait()、Thread.join()、LockSupport.park()) │ RUNNABLE ←→ TIMED_WAITING(Thread.sleep()、Object.wait(long)、LockSupport.parkNanos()) │ RUNNABLE → TERMINATED

1.3 各状态详解

NEW(新建)
// 创建线程,但未启动Threadthread=newThread(()->System.out.println("Hello"));// 状态:NEW
RUNNABLE(可运行)
// 启动线程thread.start();// 状态:RUNNABLE(可能正在运行,也可能等待 CPU 时间片)
BLOCKED(阻塞)
// 等待获取 synchronized 锁synchronized(lock){// 线程进入 BLOCKED 状态,等待获取锁}
WAITING(无限期等待)
// Object.wait()synchronized(lock){lock.wait();// 释放锁,进入 WAITING}// Thread.join()thread.join();// 等待 thread 结束// LockSupport.park()LockSupport.park();// 阻塞当前线程
TIMED_WAITING(超时等待)
// Thread.sleep()Thread.sleep(1000);// 1 秒// Object.wait(long)synchronized(lock){lock.wait(1000);// 最多等 1 秒// Thread.join(long)thread.join(1000);// LockSupport.parkNanos()LockSupport.parkNanos(1000000);// 1 毫秒
TERMINATED(终止)
// 线程执行完毕thread.join();// 等待 thread 结束// 状态:TERMINATED

2. 线程的创建与启动 🚀

2.1 继承 Thread

classMyThreadextendsThread{@Overridepublicvoidrun(){System.out.println("Thread running");}}// 启动MyThreadt=newMyThread();t.start();

2.2 实现 Runnable

classMyRunnableimplementsRunnable{@Overridepublicvoidrun(){System.out.println("Runnable running");}}// 启动Threadt=newThread(newMyRunnable());t.start();// Lambda 简化Threadt=newThread(()->System.out.println("Lambda running"));t.start();

2.3 实现 Callable

classMyCallableimplementsCallable<Integer>{@OverridepublicIntegercall()throwsException{return42;}}// 启动(需要 FutureTask)FutureTask<Integer>task=newFutureTask<>(newMyCallable());newThread(task).start();Integerresult=task.get();// 获取返回值

2.4 线程池

// 创建线程池ExecutorServiceexecutor=Executors.newFixedThreadPool(4);// 提交任务executor.submit(()->System.out.println("Task running"));// 关闭executor.shutdown();

3. synchronized 基础 🔐

3.1 什么是 synchronized?

synchronized是 Java 的内置锁,保证同一时刻只有一个线程执行同步代码块。

// 修饰实例方法publicsynchronizedvoidincrement(){count++;}// 修饰代码块publicvoidincrement(){synchronized(this){count++;}}// 修饰静态方法publicstaticsynchronizedvoidstaticIncrement(){staticCount++;}

3.2 synchronized 的特性

特性说明
原子性保证代码块原子执行
可见性保证内存可见性
阻塞性未获取锁的线程阻塞
可重入同一个线程可以多次获取

3.3 可重入性

publicsynchronizedvoidmethodA(){System.out.println("A");methodB();// 可以重入}publicsynchronizedvoidmethodB(){System.out.println("B");}// 同一个线程可以多次获取锁

3.4 synchronized 的使用场景

// 场景 1:计数器privateintcount=0;publicsynchronizedvoidincrement(){count++;}publicsynchronizedintgetCount(){returncount;}// 场景 2:单例模式publicclassSingleton{privatestaticSingletoninstance;publicstaticsynchronizedSingletongetInstance(){if(instance==null){instance=newSingleton();}returninstance;}}// 场景 3:生产者-消费者publicclassBuffer{privateQueue<String>queue=newLinkedList<>();privateintcapacity=10;publicsynchronizedvoidput(Stringitem)throwsInterruptedException{while(queue.size()>=capacity){wait();// 等待消费者消费}queue.add(item);notifyAll();// 通知消费者}publicsynchronizedStringtake()throwsInterruptedException{while(queue.isEmpty()){wait();// 等待生产者生产}Stringitem=queue.poll();notifyAll();// 通知生产者returnitem;}}

4. synchronized 底层原理 🔧

4.1 Monitor(监视器锁)

synchronized底层依赖Monitor(监视器锁)实现:

Monitor 结构: │ ├─ Owner:拥有锁的线程 ├─ WaitSet:等待队列(调用 wait() 的线程) ├─ EntryList:阻塞队列(等待获取锁的线程) └─ Count:计数器(重入次数)

4.2 锁的升级过程

synchronized锁会根据竞争情况自动升级

锁升级过程: │ ├─ 无锁 │ ├─ 偏向锁(第一次获取锁) │ └─ 记录线程 ID,下次进入无需同步 │ ├─ 轻量级锁(多个线程竞争) │ └─ 自旋 CAS 获取锁 │ └─ 重量级锁(自旋失败) └─ 阻塞等待

4.3 偏向锁

第一次获取锁时,使用偏向锁:

// 偏向锁:记录线程 ID// 下次同一线程进入同步块,无需任何同步操作synchronized(this){// ...}

优点:无同步开销
缺点:有竞争时需要撤销

4.4 轻量级锁

多个线程交替获取锁时,使用轻量级锁:

// 轻量级锁:CAS 自旋// 线程在栈帧中创建锁记录(Lock Record)// 通过 CAS 将锁记录地址复制到对象头的 Mark Wordsynchronized(this){// ...}

优点:避免线程阻塞
缺点:自旋消耗 CPU

4.5 重量级锁

多线程竞争激烈时,升级为重量级锁:

// 重量级锁:Monitor 机制// 未获取锁的线程阻塞,等待唤醒synchronized(this){// ...}

优点:竞争激烈时效率高
缺点:线程阻塞,切换开销大


5. 常见问题与注意事项 ⚠️

5.1 锁对象不能为 null

// ❌ 错误Objectlock=null;synchronized(lock){// NullPointerException}// ✅ 正确Objectlock=newObject();synchronized(lock){}

5.2 锁的范围要适当

// ❌ 锁范围过大publicsynchronizedvoidprocess(){// 大量无需同步的代码downloadFile();// 耗时操作parseData();saveToDb();}// ✅ 锁范围适当publicvoidprocess(){downloadFile();parseData();synchronized(this){saveToDb();// 只锁关键部分}}

5.3 避免死锁

// ❌ 可能死锁publicvoidmethod1(){synchronized(lockA){synchronized(lockB){// ...}}}publicvoidmethod2(){synchronized(lockB){// 顺序相反synchronized(lockA){// ...}}}// ✅ 统一锁顺序publicvoidmethod1(){synchronized(lockA){synchronized(lockB){// ...}}}publicvoidmethod2(){synchronized(lockA){// 顺序一致synchronized(lockB){// ...}}}

5.4 静态 synchronized vs 实例 synchronized

classUser{// 锁的是 User.class 对象publicstaticsynchronizedvoidstaticMethod(){// 同一时刻只有一个线程执行}// 锁的是 this(实例对象)publicsynchronizedvoidinstanceMethod(){// 同一时刻只有一个线程执行(同一实例)}}

6. 常见面试题 📝

6.1 synchronized 和 Lock 的区别?

特性synchronizedLock
语法关键字接口
获取锁自动释放手动获取/释放
阻塞可选择
公平锁可选择
条件变量

6.2 synchronized 修饰 static 方法和普通方法的区别?

  • static 方法:锁的是 Class 对象
  • 普通方法:锁的是 this(实例对象)

6.3 什么是可重入锁?

同一个线程可以多次获取同一把锁,不会被自己阻塞。

6.4 锁升级的过程?

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

6.5 如何排查死锁?

# jstack 排查死锁jstack<pid># 输出包含 "Found 1 deadlock."

小结

  • 线程六种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
  • 线程创建:继承 Thread、实现 Runnable、实现 Callable、线程池
  • synchronized:保证原子性、可见性、可重入
  • 锁升级:偏向锁 → 轻量级锁 → 重量级锁
  • 注意事项:锁对象不能为 null、锁范围要适当、避免死锁

下一篇(027)预告volatile、happens-before 入门——可见性、指令重排、内存屏障、JMM 模型。

http://www.jsqmd.com/news/710176/

相关文章:

  • 智能体与工作流:自动化技术的核心范式对比与实践
  • 2026年白洋淀住宿优质选择推荐:白洋淀望月岛10号院,雄安白洋淀民宿、白洋淀农家院、民宿体验、包吃住服务、整院出租、渔船接送以原生态水乡体验守护短途出行美好 - 海棠依旧大
  • 3步解锁大脑奥秘:OpenBCI GUI完整脑机接口入门指南
  • 2026年4月电阻及电阻柜厂家最新推荐:中性点接地电阻、负载电阻柜、制动电阻、梯形铝壳电阻、大功率电阻器、假性负载测试电阻柜厂家优选指南 - 海棠依旧大
  • 机器学习评估指标详解:从原理到实践
  • claude code在pycharm中的安装使用
  • 5步掌握ASMR音频资源高效下载:asmr-downloader工具完全指南
  • ChatGPT的Prompt处理机制与优化策略
  • AgentBench:大模型智能体综合能力评估基准详解与实战指南
  • 2026年暗管漏水检测公司推荐|精准定位管道漏水点,覆盖家庭厂区多场景 - 海棠依旧大
  • 大型语言模型如何革新自动化科学发现
  • 对于线程的思路
  • GPT-5.5编码效率全面提升
  • Act2Goal:基于视觉世界模型和多尺度时序控制的机器人框架
  • 军工项目交付倒计时48小时,固件突然被注入恶意跳转指令?教你用3步LLVM IR级插桩+编译期符号剥离紧急止血
  • 风控处置中心怎么设计 别只讲概念,真正容易出问题的是链路、状态和治理
  • 三步彻底解决惠普OMEN性能限制:开源硬件控制工具终极指南
  • 20251909-2025-2026-2 《网络攻防实践》实践8报告
  • 谁能实现工厂数据智能化,谁就拥有开启工业5.0的钥匙?
  • BetterJoy:终极Switch控制器跨平台无缝集成方案
  • 写给做系统设计 / 项目实战的你:设备指纹系统怎么设计
  • 低轨卫星实时任务功耗黑洞(Tickless模式失效、浮点陷阱、Cache预热冗余)及航天院所内部禁用清单
  • 仅限TOP20工业自动化厂商内部流通:C语言Modbus网关安全扩展SDK v3.2.1(含FIPS 140-3认证加密模块源码)
  • 告别数据库臃肿:手把手教你用SQL脚本+SSMS给SQL Server 2019/2022做“瘦身手术”
  • DragMesh技术:轻量级3D交互生成的核心突破
  • 蓝桥杯嵌入式备赛:用STM32CubeMX搞定按键、LCD和ADC的完整配置清单
  • QuickLookVideo:突破macOS原生限制的视频预览效率倍增器
  • 从玩具车到无人机:手把手教你用Simulink搭建一个带干扰的闭环速度控制系统
  • 向量检索系统中Ground-Truth-Aware评估指标的设计与实践
  • 时间折叠术:软件测试从业者的效率跃迁与未来应对策略