当前位置: 首页 > 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.dtcms.com/a/344979.html

相关文章:

  • RK3506-PWM计数功能
  • c#实现鼠标mousemove事件抽稀,避免大数据阻塞网络
  • 【COMSOL】Comsol学习案例时的心得记录分享(三)
  • 罗技鼠标驱动下载教程 多种方法详细说明
  • 排序---插入排序
  • CS 创世 SD NAND 助力 T-BOX:破解智能汽车数字中枢的存储密码
  • 110、【OS】【Nuttx】【周边】效果呈现方案解析:查找最新构建件
  • C++/QT 开发技能树详解
  • 钉钉 Stream 模式SpringBoot接入配置与事件监听
  • Maxscript如何清理3dMax场景?
  • react样式问题
  • git旧仓库迁移到新仓库
  • [系统架构设计师]安全架构设计理论与实践(十八)
  • Web3与AI语境下的审美积累:HAQQ品牌识别解析
  • 多人编程新方式:cpolar 让 OpenHands 远程开发更轻松
  • 区块链技术原理(17)-以太坊网络
  • SpringBoot中的条件注解
  • 常用三角函数公式推导体系
  • LLM应用场景能力边界趋势全览
  • 从系统修复到硬件检测的技术实测
  • [antv-x6] 文档链接
  • 08高级语言逻辑结构到汇编语言之逻辑结构转换 continue break 完结汇编按逻辑结构
  • RCE的CTF题目环境和做题复现第4集
  • 驱动(二)系统移植
  • 根据webpack设计原理手写一个简版webpack
  • 亚马逊广告优化新逻辑:从人工苦力到AI智能的进化之路
  • K8S的部署与常用管理
  • http请求有哪些?
  • 文件相关操作的函数和文件操作
  • 使用tensorRT8部署yolov5目标检测模型(1)