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

【Java并发编程】Java多线程深度解析:状态、通信与停止线程的全面指南

Java多线程深度解析:状态、通信与停止线程的全面指南 🚀

文章目录

  • Java多线程深度解析:状态、通信与停止线程的全面指南 🚀
    • Java线程与操作系统线程的关系
    • 使用多线程要注意的问题
    • 保证数据一致性的方案
    • 线程的创建方式
    • 如何停止一个线程的运行
    • Java线程的状态有哪些? 🌀
    • sleep和wait的区别是什么? ⏳
    • sleep会释放CPU吗? 💤
    • blocked和waiting有啥区别? 🔄
    • wait状态下的线程如何进行恢复到running状态? 🔄
    • notify和notifyAll的区别? 📢
    • notify选择哪个线程? ❓
    • 不同的线程之间如何通信? 📞
    • 线程间通信方式有哪些? 📨
    • 如何停止一个线程? ⛔


Java线程与操作系统线程的关系

是的,Java线程与操作系统线程是一一对应的。Java底层通过调用pthread_create(在Unix-like系统上)或类似的系统API来创建线程,因此Java线程本质上是操作系统级别的线程。这意味着Java线程的调度和管理由操作系统内核负责,确保了多线程程序的并发执行能力。


使用多线程要注意的问题

  1. 原子性 🔒

    • 问题:多个线程同时修改共享数据可能导致数据不一致。
    • 解决方案:使用synchronized关键字或ReentrantLock确保同一时刻只有一个线程能访问临界区。
    public class Counter {private int count = 0;public synchronized void increment() {count++;}
    }
    
  2. 可见性 👀

    • 问题:一个线程修改了共享变量,其他线程可能看不到最新值。
    • 解决方案:使用volatile关键字或synchronized确保修改立即对其他线程可见。
    private volatile boolean flag = false;
    
  3. 有序性 🔄

    • 问题:指令重排序可能导致程序行为异常。
    • 解决方案:遵循happens-before原则,使用volatilesynchronized防止重排序。

保证数据一致性的方案

方案描述
数据库事务使用ACID事务确保数据操作要么全部成功,要么全部回滚。
锁机制通过synchronizedReentrantLock保证同一时刻只有一个线程修改数据。
版本控制使用乐观锁(如CAS操作)或版本号避免并发修改冲突。

线程的创建方式

  1. 继承Thread类

    • 优点:简单直接,可直接使用this获取当前线程。
    • 缺点:无法继承其他类。
    class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread is running");}
    }
    // 启动线程
    new MyThread().start();
    
  2. 实现Runnable接口

    • 优点:可继承其他类,适合多个线程共享同一资源。
    • 缺点:需通过Thread.currentThread()获取当前线程。
    class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable is running");}
    }
    // 启动线程
    new Thread(new MyRunnable()).start();
    
  3. 实现Callable接口

    • 优点:可返回结果和抛出异常,适合需要返回值的任务。
    • 缺点:需通过FutureTask包装。
    class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "Callable result";}
    }
    // 启动线程
    FutureTask<String> task = new FutureTask<>(new MyCallable());
    new Thread(task).start();
    System.out.println(task.get());
    
  4. 线程池

    • 优点:避免频繁创建和销毁线程,提高性能。
    • 缺点:配置复杂,需注意参数调优。
    ExecutorService executor = Executors.newFixedThreadPool(5);
    executor.submit(() -> System.out.println("Task executed by thread pool"));
    executor.shutdown();
    

如何停止一个线程的运行

方法描述代码示例
异常法停止通过interrupt()设置中断状态,在run方法中检查并抛出异常。if (Thread.interrupted()) throw new InterruptedException();
在沉睡中停止调用interrupt()会中断阻塞状态(如sleep),并抛出InterruptedExceptiontry { Thread.sleep(1000); } catch (InterruptedException e) { return; }
stop()暴力停止已弃用,可能导致数据不一致或资源未释放。不推荐使用
return停止检查中断状态后直接return退出run方法。if (Thread.interrupted()) return;

Java线程的状态有哪些? 🌀

Java线程的生命周期包括以下6种状态(参考Thread.State枚举):

  1. NEW:新建状态,线程被创建但尚未启动。
  2. RUNNABLE:可运行状态,包括正在运行或准备就绪等待CPU调度。
  3. BLOCKED:阻塞状态,线程等待获取监视器锁(如进入synchronized块)。
  4. WAITING:等待状态,线程等待其他线程显式唤醒(如调用Object.wait()Thread.join())。
  5. TIMED_WAITING:超时等待状态,线程等待特定时间后自动唤醒(如Thread.sleep(1000)Object.wait(1000))。
  6. TERMINATED:终止状态,线程执行完毕或异常退出。

sleep和wait的区别是什么? ⏳

特性sleepwait
所属类Thread的静态方法Object的实例方法
释放锁❌ 不释放锁✅ 释放锁
使用条件无需在同步块中调用必须在同步块中调用(需先获取锁)
唤醒方式时间到自动唤醒需其他线程调用notify()/notifyAll()
// sleep示例
Thread.sleep(1000); // 当前线程休眠1秒,不释放锁// wait示例
synchronized (lock) {lock.wait(); // 释放锁,进入等待状态
}

sleep会释放CPU吗? 💤

会的!

  • sleep()方法会让当前线程主动放弃CPU资源,进入TIMED_WAITING状态,但不会释放持有的锁
  • 其他线程可以竞争CPU时间片,但由于锁未被释放,其他线程无法进入同一同步块。

blocked和waiting有啥区别? 🔄

状态触发条件锁的持有情况
BLOCKED等待进入synchronized块或方法未获取锁,等待锁释放
WAITING调用wait()join()等方法已获取锁,但主动释放并等待唤醒
  • BLOCKED是“进不去”,WAITING是“进去了但主动出来等”。

wait状态下的线程如何进行恢复到running状态? 🔄

  1. 其他线程调用相同锁对象notify()notifyAll()方法。
  2. 线程被唤醒后需重新竞争锁,获取锁后才能继续执行。
synchronized (lock) {lock.wait(); // 释放锁并等待// 被唤醒后需重新获取锁才能继续执行
}

notify和notifyAll的区别? 📢

方法作用使用场景
notify()随机唤醒一个等待同一锁的线程多个线程等待同一资源,但只需唤醒一个
notifyAll()唤醒所有等待同一锁的线程需唤醒所有线程以避免信号丢失

⚠️ 注意:唤醒的线程仍需竞争锁,只有获取锁的线程能进入RUNNABLE状态。


notify选择哪个线程? ❓

notify()的选择是随机的!

  • JVM不保证唤醒的顺序,因此依赖唤醒顺序的程序可能产生非确定性行为。
  • 建议使用notifyAll()或更高级的同步工具(如Condition)。

不同的线程之间如何通信? 📞

线程通信主要通过共享内存等待/通知机制实现:

  1. 共享变量:使用volatilesynchronized保证可见性。
  2. 等待/通知:使用wait()notify()notifyAll()
  3. 管道流:使用PipedInputStream/PipedOutputStream
  4. 高级工具:如CountDownLatchCyclicBarrierBlockingQueue等。

线程间通信方式有哪些? 📨

方式描述
synchronized + wait/notify基础通信机制,需在同步块中使用。
Lock + Condition更灵活的通信方式,支持多个条件队列。
BlockingQueue线程安全的队列,天然支持生产者-消费者模型。
CountDownLatch/CyclicBarrier同步工具,用于线程间协调。
volatile变量轻量级通信,保证可见性但不保证原子性。
// BlockingQueue示例
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
// 生产者
queue.put("message");
// 消费者
String message = queue.take();

如何停止一个线程? ⛔

  1. 使用interrupt()中断

    • 设置中断标志,线程需检查中断状态并主动退出。
    public void run() {while (!Thread.currentThread().isInterrupted()) {// 执行任务}
    }
    // 外部调用
    thread.interrupt();
    
  2. 使用标志位

    • 通过自定义volatile变量控制线程退出。
    private volatile boolean stopped = false;
    public void run() {while (!stopped) {// 执行任务}
    }
    // 外部设置
    stopped = true;
    
  3. 避免使用stop()

    • stop()已废弃,可能导致数据不一致或资源泄漏。

希望这篇全面解析能帮助你深入理解Java多线程!如果有任何问题,欢迎留言讨论 😊。

http://www.xdnf.cn/news/1345177.html

相关文章:

  • 多态(polymorphism)
  • celery
  • 学习python第12天
  • 基于Python的伊人酒店管理系统 Python+Django+Vue.js
  • 探索Thompson Shell:Unix初代Shell的智慧
  • Linux之Ubuntu入门:Vmware中虚拟机中的Ubuntu中的shell命令-常用命令
  • 解决 PyTorch 导入错误:undefined symbol: iJIT_NotifyEvent
  • MTK Linux DRM分析(十一)- MTK KMS Panel显示屏驱动
  • 使用html+css+javascript练习项目布局--创建导航栏
  • Linux驱动开发笔记(六)——pinctrl GPIO
  • MTK Linux DRM分析(十三)- Mediatek KMS实现mtk_drm_drv.c(Part.1)
  • chapter07_初始化和销毁方法
  • 【连接器专题】连接器接触界面的理解
  • CoreShop微信小程序商城框架开启多租户-添加一个WPF客户端以便进行本地操作--读取店铺信息(6)
  • 彩笔运维勇闯机器学习--最小二乘法的数学推导
  • 在线教育领域的视频弹题功能如何打造高互动性在线课程
  • 【Tech Arch】Hadoop YARN 大数据集群的 “资源管家”
  • 全栈开发:从LAMP到云原生的技术革命
  • Kali Linux 发布重构版Vagrant镜像:通过命令行快速部署预配置DebOS虚拟机
  • Pandas中的SettingWithCopyWarning警告出现原因及解决方法
  • DbLens:告别手动Mock数据,右键一键智能生成数据库内容
  • httpclient与hertzclient在处理Host header时的差别
  • 【GPT入门】第53课 LlamaFactory微调效果与vllm部署效果不一致问题解决
  • open webui源码分析6-Function
  • FPGA学习笔记——简单的IIC读写EEPROM
  • FPGA高端项目:图像采集+Aurora 8B10B+UDP图传架构,基于GTH高速收发器的光口转网口,提供工程源码和技术支持
  • IntelliJ IDEA 常用快捷键笔记(Windows)
  • SRE系列(二) | 从可用性到 SLI/SLO
  • 【数据结构】B 树——高度近似可”独木成林“的榕树——详细解说与其 C 代码实现
  • MySQL编程开发(了解)