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

JavaEE 多线程第四节 (线程核心操作----线程开始/线程终止)

目录

1. start() 和 run() :

总结:

2. 线程的终止控制

例子

2. lambda表达式中的变量捕获

例子

3. 为什么需要“有效final”

总结


1. start()run()

  • start() 方法
    • 负责通知 JVM 和操作系统创建新线程。
    • 新线程被调度时,会调用 run() 方法,线程的任务会在新线程中运行。
    • 只能调用一次,重复调用会抛出 IllegalThreadStateException 异常。
Thread t = new Thread(() -> {
    System.out.println("Thread is running");
});

// 正确的用法,启动新线程
t.start();  

// 错误的用法,重新启动线程会抛出 IllegalThreadStateException
t.start();  // 抛出异常
  • run() 方法
    • 定义线程的实际执行内容,但不会创建新线程。
    • 如果直接调用 run(),它只是在当前线程中执行代码,而不创建新的执行线程
Thread t = new Thread(() -> {
    System.out.println("Thread is running");
});

// 错误:这只是普通的方法调用,没有创建新线程
t.run();  // 直接在主线程执行,没有创建新的线程

总结:

  • start() 是启动线程的正确方法,它调用 run() 来执行任务,并通过底层系统 API 创建真正的操作系统级线程。
  • 不能在同一个线程对象上调用 start() 两次,否则会抛出 IllegalThreadStateException
  • run() 方法可以被直接调用,但它不会启动新线程,而是在当前线程执行任务。

2. 线程的终止控制

在Java中,主线程和子线程之间的协作是重要的。比如在一个子线程中运行一个无限循环,当某个条件满足时终止这个循环。常用的控制方式是通过一个共享变量,让主线程更新这个变量,然后子线程检查变量值来决定是否退出。

例子
public class Demo01 {
    private static boolean isQuit = false;

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (!isQuit) {
                System.out.println("hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("子线程结束");
        });
        
        t.start();
        
        // 主线程等待2秒后,将isQuit置为true
        Thread.sleep(2000);
        isQuit = true;
        System.out.println("主线程设置isQuit=true,通知子线程结束");
    }
}

在这个例子中,isQuit变量被主线程和子线程共享。主线程在2秒后将isQuit置为true,从而通知子线程结束循环。这种方法简单直接,但在多线程环境中需要确保isQuit变量的可见性(即使用volatile关键字或其他同步手段)。

2. lambda表达式中的变量捕获

在Java中,lambda表达式中引用的外部变量必须是**"有效final"**的(即变量的值在lambda表达式内部不能更改)。这个限制主要是因为lambda表达式会将变量“捕获”到内部类的作用域中去,而该变量必须是不可变的。

例子

在以下代码中,如果将共享变量isQuit直接放入lambda表达式中,必须确保其不可变或使用final修饰。

public class Demo02 {
    private static boolean isQuit = false;

    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            while (!isQuit) {
                System.out.println("hello");
            }
        });
        
        t.start();
    }
}

如果在lambda表达式中修改了isQuit的值,则会报错,因为Java不允许在lambda中修改捕获的非final变量。

3. 为什么需要“有效final”

在Java的并发编程中,lambda表达式和匿名类具有闭包特性,这意味着它们可以引用外部作用域的变量,但变量必须是不可变的。这背后的原因包括以下几点:

  • 线程安全:不可变的变量在并发情况下是线程安全的。
  • 内存模型:Java的内存模型对线程间的变量可见性有严格要求,不可变变量可以保证不会被其他线程修改,从而简化了JVM的实现。

总结

  1. 使用isQuit控制线程的退出,主线程可以在某个时间点设置isQuittrue,从而通知子线程退出。
  2. lambda表达式中捕获外部变量时需要保证变量是不可变的,即有效final
  3. 使用volatile可以保证多线程环境中变量的可见性

http://www.kler.cn/a/373365.html

相关文章:

  • zynq PS端跑Linux响应中断
  • 奥数与C++小学四年级(第十二题 装礼盒)
  • LINUX IIC总线驱动-设备框架
  • c++应用网络编程之十三Linux下的epoll模式应用
  • Atlas800昇腾服务器(型号:3000)—SwinTransformer等NPU推理【图像分类】(九)
  • uniapp通过id获取div的宽度,高度,位置等(应该是 任意平台都通用 )
  • 【机器学习】线性回归模型
  • Linux系统rpm安装MySQL详细操作步骤
  • 19 Docker容器集群网络架构:二、etcd 集群部署
  • 【Java多线程】8 Java 中的并发设计模式
  • 【K8S系列】Kubernetes 中 NodePort 类型的 Service 无法访问的问题【已解决】
  • MySQL(2)【库的操作】
  • python爬虫案例——使用aiohttp模块异步请求网站,利用协程加快爬取速度(17)
  • 数据可视化工具深入学习:Seaborn 与 Plotly 的详细教程
  • Linux驱动开发(1):环境搭建
  • 工厂方法模式与抽象工厂模式
  • 九泰智库 | 医械周刊- Vol.65 | 广州发布首批创新药械产品目录
  • libavdevice.so.58: cannot open shared object file: No such file ordirectory踩坑
  • XXE漏洞原理、修复建议及绕过方式
  • 蓝牙4.0/5.1/5.2模组UART通讯基础知识
  • 【C++动态规划】有效括号的嵌套深度
  • 【Triton 教程】矩阵乘法
  • 新闻列表以及详情页面梳理
  • DAY66WEB 攻防-Java 安全SPEL 表达式SSTI 模版注入XXEJDBCMyBatis 注入
  • Linux find 匹配文件内容
  • 无损将GPT转换为MBR的GDisk操作指南: