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

13.多线程通关秘籍:用售票系统讲透 Java 线程创建与 synchronized 锁魔法

一、当火车站遇见多线程:售票大厅的热闹日常​

        想象一个春运期间的火车站售票大厅:10 个售票窗口同时开放,每个窗口都在疯狂出售通往家乡的车票。这就是现实世界中的 "多线程" 场景 —— 多个任务(售票窗口)同时运行,共享同一批资源(车票)。在 Java 的世界里,线程就是这样的 "售票员",它们能让程序像热闹的售票大厅一样高效运转。​

        但如果管理不当,就会出现魔幻场景:明明只剩 10 张票,却卖出了 15 张;甚至出现负数车票的情况。这就是线程安全问题!今天我们就用这个真实场景,揭开 Java 多线程的神秘面纱。​

二、线程创建的两种姿势:继承派 vs 接口派​

1. 继承 Thread 类:简单直接的 "单线程体"

// 第一种姿势:继承Thread类
class TicketSeller extends Thread {private int tickets = 100; // 初始100张票@Overridepublic void run() { // 线程执行体,相当于售票员的工作while (tickets > 0) {try {Thread.sleep(50); // 模拟售票操作耗时} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余:" + --tickets);}}
}public class ThreadDemo {public static void main(String[] args) {// 创建3个售票窗口(线程)new TicketSeller().start(); // 窗口1开始工作new TicketSeller().start(); // 窗口2开始工作new TicketSeller().start(); // 窗口3开始工作}
}

        运行结果可能出现 "剩余:-5" 这样的魔幻场景!因为每个售票员(线程)都有自己的独立票箱(tickets 变量),相当于开了 3 个独立窗口卖 300 张票,这显然不符合现实场景!​

2. 实现 Runnable 接口:共享资源的正确打开方式

// 第二种姿势:实现Runnable接口(推荐!)
class SharedTicketSeller implements Runnable {private int tickets = 100; // 重点!共享同一批车票@Overridepublic void run() {while (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余:" + --tickets);}}
}public class RunnableDemo {public static void main(String[] args) {SharedTicketSeller seller = new SharedTicketSeller(); // 唯一的票箱// 3个窗口共享同一个票箱new Thread(seller, "窗口A").start();new Thread(seller, "窗口B").start();new Thread(seller, "窗口C").start();}
}

        这次 3 个窗口共享同一批车票,但运行后依然可能出现负数!因为多个线程同时操作 tickets 变量时,出现了 "非原子性操作"—— 就像两个售票员同时看到剩余 1 张票,都认为自己能卖出,结果卖出 2 张票。​

三、线程同步:给票箱加把 "原子锁"​

1. 问题根源:魔幻操作的三步曲

当线程执行--tickets时,实际分为 3 步:​

  1. 读取 tickets 值(比如 1)​
  2. 执行减 1 操作(得到 0)​
  3. 写回 tickets 变量​

        如果两个线程同时执行到第一步,都读取到 1,就会各自减 1,最终得到 - 1,这就是经典的线程安全问题

2. synchronized 关键字:给操作加锁​

class SafeTicketSeller implements Runnable {private int tickets = 100;private Object lock = new Object(); // 锁对象,相当于票箱的钥匙@Overridepublic void run() {while (tickets > 0) {synchronized (lock) { // 只有拿到钥匙才能操作if (tickets > 0) { // 二次检查(双重校验锁雏形)try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余:" + --tickets);}} // 离开代码块自动释放锁}}
}

锁的工作原理:​

  1. 当线程 A 进入synchronized代码块,会获取 lock 对象的锁,其他线程只能在门外排队​
  2. 线程 A 执行完毕或异常退出时,自动释放锁,下一个线程才能进入​
  3. 确保同一时间只有一个线程操作共享资源(票箱),就像每次只有一个售票员能打开票箱数票

3. 锁的高级用法:直接锁方法​

class MethodLockSeller implements Runnable {private int tickets = 100;@Overridepublic synchronized void run() { // 等价于synchronized(this)while (tickets > 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "卖出1张票,剩余:" + --tickets);}}
}

        这里锁的是当前对象(this),适合锁实例方法的场景,但要注意:静态方法锁的是类对象,普通方法锁的是实例对象。​

四、两种创建方式对比:选对工具很重要

特性

继承 Thread 类

实现 Runnable 接口

资源共享

每个线程独立对象

多个线程共享同一实例

扩展性

单继承限制(Java 不支持多继承)

可同时继承其他类 / 实现多个接口

设计模式

面向对象(is-a 关系)

面向接口(has-a 关系,推荐)

适用场景

简单独立任务

多线程共享资源场景

        最佳实践:永远优先使用 Runnable 接口!就像现实中售票员可以同时是收银员(实现多个接口),而继承 Thread 类就像让售票员只能当售票员,扩展性太差。​

 

五、总结:多线程世界的生存法则​

  1. 线程创建:用 Runnable 实现共享资源,避免继承 Thread 的单继承局限​
  2. 线程安全:遇到共享资源(如票箱、账户余额),记得用 synchronized 加锁​
  3. 锁的范围:尽量缩小锁的作用域(只锁关键代码),提高并发效率​
  4. 调试技巧:用Thread.currentThread().getName()定位问题线程,用jstack命令查看线程堆栈​

        下次当你在火车站看到多个售票窗口时,不妨想想 Java 的多线程:每个窗口就是一个线程,票箱就是共享资源,而 synchronized 就是那个确保秩序的神奇锁。掌握这些,你就能在并发编程的世界里畅通无阻!

相关文章:

  • 移动零 - 简单
  • Java基础 Day24
  • 闲鱼到淘宝商品同步的技术实现原理与局限
  • 5.29 打卡
  • MCP(模型上下文协议)深度解析:一篇文章彻底理解
  • AI新手入门解锁元生代MaaS平台:API工作流调用全攻略
  • DMBOK对比知识点对比(1)
  • 关系型数据库与非关系型数据库的区别
  • 涂鸦智能的TuyaOpen框架入门指南:智能插座实战
  • Vue 组件 - 指令
  • Python中re模块结合正则表达式的应用
  • springboot拦截器的基本配置
  • OSCP备战-SickOs1.2靶场详细步骤
  • WPF 按钮悬停动画效果实现
  • 大数据如何赋能市场情报分析?——精准决策,从数据开始
  • Bently Nevada 135473-01振动监控模块3500系列状态系统
  • 强化学习极简入门笔记
  • 技术文档撰写指南:从结构到细节的全流程解析
  • 小白玩串口控制的ASCII避坑
  • 计算机网络常见体系结构、分层必要性、分层设计思想以及专用术语介绍
  • 域名停靠app/成都seo公司
  • hao123网址怎么删除/seo基础课程
  • wordpress数据互通/优化模型的推广
  • 自动卖卡密的网站怎么做/灰色关键词怎么做排名
  • 回力网站建设初衷/百度关键词规划师
  • wordpress 嵌入html/信息流优化师简历怎么写