【Java并发编程 | JUC】线程

news2025/1/11 11:12:34

Java 线程

项目配置

pom.xml

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
</dependencies>

logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration
        xmlns="http://ch.qos.logback/xml/ns/logback"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback logback.xsd">
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%date{HH:mm:ss} [%t] %logger - %m%n</pattern>
        </encoder>
    </appender>
    <logger name="c" level="debug" additivity="false">
        <appender-ref ref="STDOUT"/>
    </logger>
    <root level="ERROR">
        <appender-ref ref="STDOUT"/>
    </root>
</configuration>

多线程概述

进程与线程

程序:一组静态的指令集

进程:程序运行的一个实例

线程:进程中的一个执行单元

并行与并发

并发 concurrent:单个核心通过任务调度器,线程轮流使用 CPU

并行 parallel:多个核心同时运行

同步与异步

同步:需要等待返回

异步:不需要等待返回

I/O 操作不占用 CPU

创建线程

Thread 类

@Slf4j(topic = "c.App")
public class App {
    public static void main(String[] args) {
        Thread t = new Thread(() -> log.info("Thread t"));
        t.setName("t");
        t.start();
        log.info("Thread main");
    }
}

Runable 接口

将任务和线程分离,代码更灵活

组合优于基础

@Slf4j(topic = "c.App")
public class App {
    public static void main(String[] args) {
        Runnable func = () -> log.info("Thread t");
        Thread t = new Thread(func, "t");
        t.start();
        log.info("Thread main");
    }
}

Callable 接口 & FutureTask 类

@Slf4j(topic = "c.App")
public class App {
    public static void main(String[] args) 
        throws ExecutionException, InterruptedException {
        FutureTask<Integer> task = new FutureTask<>(() -> {
            log.info("Thread t running");
            Thread.sleep(1000);
            return 114514;
        });
        new Thread(task, "t").start();
        Integer res = task.get();
        log.info("Thread main - {}", res);
    }
}

线程运行的原理

栈与栈帧

每个线程都有一个栈,栈内有多个栈帧,每个栈帧对定一个方法。

每个线程只有一个活动帧(栈顶的栈帧),对应正在执行的方法。

线程上下文切换

导致 cpu 切换运行其他线程的原因:

  1. 线程时间片用完
  2. 垃圾回收
  3. 有更高优先级进程
  4. 线程调用了 sleep、wait 等方法

线程上下文切换时需要保存进程状态,并恢复另一个线程状态。

Thread 类方法

API

方法说明
public void start()启动一个新线程,Java虚拟机调用此线程的 run 方法
public void run()线程启动后调用的方法
public void setName(String name)给当前线程取名字
public void getName()获取当前线程的名字
默认名称:子线程是 Thread-索引,主线程是 main
public static Thread currentThread()获取当前线程对象,代码在哪个线程中执行
public static void sleep(long time)让当前线程休眠多少毫秒再继续执行
Thread.sleep(0) : 让操作系统立刻重新进行一次 CPU 竞争
public static native void yield()提示线程调度器让出当前线程对 CPU 的使用
public final int getPriority()返回此线程的优先级
public final void setPriority(int priority)更改此线程的优先级,常用 1 5 10
public void interrupt()中断这个线程,异常处理机制
public static boolean interrupted()判断当前线程是否被打断,清除打断标记
public boolean isInterrupted()判断当前线程是否被打断,不清除打断标记
public final void join()等待这个线程结束
public final void join(long millis)等待这个线程死亡 millis 毫秒,0 意味着永远等待
public final native boolean isAlive()线程是否存活(是否运行完毕)
public final void setDaemon(boolean on)将此线程标记为守护线程或用户线程

start() 和 run()

start():用于启动线程,不能被多次调用。线程启动前状态为 new,启动后变成 runable

run():线程启动后执行的代码

sleep()

  1. 睡眠当前线程,将当前线程状态将 running 变成 timed_waiting(阻塞状态)
  2. 其它线程可以使用 interrupt() 方法打断正在睡眠的线程,这时 sleep() 方法会抛出 InterruptedException 异常
  3. 建议使用 TimeUnit.SECOND.sleep() 代替 Thread.sleep(),提高可读性

在没有利用 cpu 来计算时,不要让 while(true) 空转浪费 cpu ,可以使用 yield() 或 sleep() 来让出 cpu 的使用权给其他程序。

yield()

  1. 让出当前线程 CPU 使用权,将当前线程状态将 running 变成 runable(就绪状态)
  2. 具体实现依赖于操作系统的任务调度区

join()

等待调用的线程结束,可以用于线程同步

@Slf4j(topic = "c.App")
public class App {
    static int num = 0;

    public static void main(String[] args) throws InterruptedException {
        log.info("before start - {}", num);
        Thread t = new Thread(() -> num = 1, "t");
        t.start();
        log.info("after start - {}", num);
        t.join();
        log.info("after join - {}", num);
    }
}
17:18:57 [main] c.App - before start - 0
17:18:57 [main] c.App - after start - 0
17:18:57 [main] c.App - after join - 1

park()

使线程进入阻塞状态,类似于断点。遇到 interrupt() 会打断 park()

@Slf4j(topic = "c.App")
public class App {

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = () -> {
            log.debug("before park()");
            LockSupport.park();
            log.debug("after park()");
        };

        Thread t = new Thread(runnable, "t");
        t.start();
        TimeUnit.SECONDS.sleep(1);
        t.interrupt();
    }
}
23:45:16 [t] c.App - before park()
23:45:17 [t] c.App - after park()

interrupt()

1、打断阻塞(sleep、wait、join、park)的线程,会清除打断状态。

@Slf4j(topic = "c.App")
public class App {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            log.debug("sleep");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                log.debug(e.getMessage());
            }
        }, "t");
        t.start();
        // 避免主线程先打断
        TimeUnit.SECONDS.sleep(1);
        log.info("interrupt");
        t.interrupt();
        // 等待标记被清除
        TimeUnit.SECONDS.sleep(1);
        log.info("t.isInterrupted() = {}", t.isInterrupted());
    }
}

21:21:47 [t] c.App - sleep
21:21:48 [main] c.App - interrupt
21:21:48 [t] c.App - sleep interrupted
21:21:49 [main] c.App - t.isInterrupted() = false

2、打断正常运行的线程,会存在打断状态。

@Slf4j(topic = "c.App")
public class App {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            log.debug("while()");
            // 使用打断标记停止线程
            while (!Thread.currentThread().isInterrupted()) ;
        }, "t");
        t.start();
        // 避免主线程先打断
        TimeUnit.SECONDS.sleep(1);
        log.info("interrupt");
        t.interrupt();
        log.info("t.isInterrupted() = {}", t.isInterrupted());
    }
}
21:21:14 [t] c.App - while (true)
21:21:15 [main] c.App - interrupt
21:21:16 [main] c.App - t.isInterrupted() = true

不推荐使用的 API

  1. stop():停止线程运行
  2. suspend():挂起(暂停)线程运行
  3. resume():恢复线程运行

如果线程持有锁,那么没有机会释放锁。

两阶段终止模式

错误思路

stop() 方法会直接停止线程。如果线程持有锁,那么没有机会释放锁。

流程分析

无异常
有异常
while(true)
有没有被打断?
料理后事
结束循环
睡眠 2s
执行监控记录
设置打断标记

代码实现

@Slf4j(topic = "c.App")
public class App {

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = () -> {
            while (true) {
                Thread thread = Thread.currentThread();
                // 监控资源
                log.debug("running");

                // 判断打断标记
                if (thread.isInterrupted()) {
                    // 释放占用资源
                    log.debug("exit...");
                    break;
                }

                // 避免大量 CPU 占用
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    thread.interrupt();
                }
            }
        };


        Thread t = new Thread(runnable, "t");
        t.start();
        TimeUnit.SECONDS.sleep(3);
        t.interrupt();
    }
}

守护线程

守护线程:只要非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。

垃圾回收器线程就是一个守护线程。

@Slf4j(topic = "c.App")
public class App {

    public static void main(String[] args) throws InterruptedException {
        Runnable runnable = () -> {
            while (true) {
                log.debug("test");
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };

        Thread t = new Thread(runnable, "t");
        t.setDaemon(true);
        t.start();
        Thread.sleep(1000);
        log.debug("main stop");
    }
}
23:59:33 [t] c.App - test
23:59:33 [t] c.App - test
23:59:33 [t] c.App - test
23:59:34 [t] c.App - test
23:59:34 [t] c.App - test
23:59:34 [main] c.App - main stop

线程的状态

五种状态

从操作系统层面描述

  1. 初始状态:创建了线程对象
  2. 可运行状态(就绪状态):线程对象与操作系统线程关联,可以被调度
  3. 运行状态:线程正在被执行
  4. 阻塞状态:线程调用了阻塞 API
  5. 终止状态:线程已经执行结束

六种状态

根据 Java 中 Thread.State 枚举类划分

  1. new:线程被创建,未调用 start() 方法
  2. runnable:运行状态 + 可运行状态 + 操作系统的阻塞状态(BIO)
  3. terminated:终止状态
  4. blocked:等待 synchronized() 获取锁
  5. waiting:等待 join()
  6. timed_waiting:有时限的阻塞状态,等待 sleep()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2112607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

orcle 数据库 day0903

ok奥家人们&#xff0c;今天继续学习orcle数据库 一. 数据完整性 向某张表插入数据、更新、删除数据之前会对数据做校验&#xff0c;目 的就是为了确保数据的正确性、一致性、最大限度 减少重复 的数据、避免脏数据&#xff0c;这就是数据完整性。以下的数据就是脏 数据&a…

表情,符号,数字,字母,加密和解密源码

表情&#xff0c;符号&#xff0c;数字&#xff0c;字母&#xff0c;加密和解密源码 可以将表情&#xff0c;动物&#xff0c;水果&#xff0c;表情&#xff0c;手势&#xff0c;猫语&#xff0c;兽语&#xff0c;狗语&#xff0c;爱语&#xff0c;符号&#xff0c;数字&#x…

Mac M1安装Hive

一、下载解压Hive 1.官网地址 https://dlcdn.apache.org/hive/ 2.选择对应版本进行下载&#xff0c;这里我以3.1.3为例&#xff1b; 3.下载好后&#xff0c;进行解压&#xff0c;并重命名为hive-3.1.3&#xff0c;放到资源库目录下&#xff1b; 二、配置系统环境 1.打开~/…

WebGL系列教程一(开篇)

目录 1 前言2 推荐的书籍和网站3 WebGL简介4 本教程包含的主要内容预览4.1 顶点着色器4.2 片元着色器4.3 绘制点线面4.4 绘制三角形和四边形4.5 缓冲区4.6 旋转、平移、缩放4.7 动画4.8 颜色和纹理4.9 GLSL语法4.10 模型变换、视图变换、投影变换4.11 光照4.12 层次模型4.13 鼠…

【MySQL】MySQL常用的数据类型——表的操作

前言&#xff1a; &#x1f31f;&#x1f31f;本期讲解关于MySQL常用数据类型&#xff0c;表的简单使用&#xff0c;希望能帮到屏幕前的你。 &#x1f308;上期博客在这里&#xff1a;http://t.csdnimg.cn/wwaqe &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondl…

传统CV算法——特征匹配算法

Brute-Force蛮力匹配 Brute-Force蛮力匹配是一种简单直接的模式识别方法&#xff0c;经常用于计算机视觉和数字图像处理领域中的特征匹配。该方法通过逐一比较目标图像中的所有特征点与源图像中的特征点来寻找最佳匹配。这种方法的主要步骤包括&#xff1a; 特征提取&#xff…

JAVA开源项目 图书个性化推荐系统 计算机毕业设计

本文项目编号 T 015 &#xff0c;文末自助获取源码 \color{red}{T015&#xff0c;文末自助获取源码} T015&#xff0c;文末自助获取源码 目录 一、系统介绍1.1 业务分析1.2 用例设计1.3 时序设计 二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究…

jmeter之循环控制器使用

一、循环控制器介绍及使用 循环控制器作用&#xff1a; 通过设置循环次数&#xff0c;来实现循环发送请求 位置&#xff1a;测试计划------>线程组(右键添加)------>逻辑控制器------>循环控制器 如图&#xff1a; 参数介绍&#xff1a; 循环次数&#xff1a;5 …

C语言11--特殊函数

静态函数 背景知识&#xff1a;普通函数都是跨文件可见的&#xff0c;即在文件 a.c 中定义的函数可以在 b.c 中使用。静态函数&#xff1a;只能在定义的文件内可见的函数&#xff0c;称为静态函数。 因此静态函数一般会被写在头文件中方便任何需要调用的文件直接包含即可作用&…

JavaScript 循环分支语句-dowhile循环

do/while 循环是 while 循环的变体。该循环会在检查条件是否为真之前执行一次代码块&#xff0c;然后如果条件为真的话&#xff0c;就会重复这个循环。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta htt…

Ansys Zemax | 什么是Sobol取样?

附件下载 联系工作人员获取附件 本文主要介绍了&#xff1a; 什么是Sobol取样&#xff1f; 和随机光线产生方法相比&#xff0c;Sobol取样有什么优点&#xff1f; Sobol取样有什么限制&#xff1f; 随机取样和Sobol取样模式 一个光源会在位置空间以及角度空间随机产生光…

前端常用工具网站分享:MemFire Cloud,懒人开发者的福音

你是否曾梦想过&#xff0c;有那么一款工具&#xff0c;能够让你像变魔术一样快速搭建起一个应用&#xff0c;而无需深陷复杂的后端搭建和接口开发的泥潭&#xff1f;今天&#xff0c;我要为你介绍的&#xff0c;就是这样一个神奇的存在——MemFire Cloud&#xff0c;一款专为懒…

1.C_数据结构_基本知识

相关名词 数据是什么&#xff1a; 数据即信息的载体&#xff0c;是能够输入到计算机中并且能够计算机识别、存储、处理的符号总称。这里的数据不一定是一个int型&#xff0c;也可能是一个语音、一个字符串或者其他的一些打包的内容。 数据元素是什么&#xff1a; 数据元素(…

Danbooru风格图片分享平台szurubooru

什么是 Danbooru &#xff1f; Danbooru 是一种流行的图片分享网站&#xff0c;以其独特的图片标签系统和搜索功能而闻名。"Danbooru风格"通常指的是模仿 Danbooru 网站的图片论坛或图片分享平台所具有的特定特征&#xff0c;如&#xff1a; 标签系统&#xff1a;用户…

代码随想录刷题day24丨93.复原IP地址 ,78.子集 , 90.子集II

代码随想录刷题day24丨93.复原IP地址 &#xff0c;78.子集 &#xff0c; 90.子集II 1.题目 1.1复原IP地址 题目链接&#xff1a;93. 复原 IP 地址 - 力扣&#xff08;LeetCode&#xff09; 视频讲解&#xff1a;回溯算法如何分割字符串并判断是合法IP&#xff1f;| LeetCod…

2024年高教杯国赛(B题)数学建模竞赛解题思路|完整代码论文集合

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

【2024高教社杯国赛A题】数学建模国赛建模过程+完整代码论文全解全析

你是否在寻找数学建模比赛的突破点&#xff1f;数学建模进阶思路&#xff01; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024国赛数学建模竞赛&#xff08;A题&#xff09;的全面解析。这个解决方案包不仅包括完整的代码实现&#xff0c;还有详尽的建模过程和解析…

WebAPI(二)、DOM事件监听、事件对象event、事件流、事件委托、页面加载与滚动事件、页面尺寸事件

文章目录 一、 DOM事件1. 事件监听2. 事件类型(1)、鼠标事件(2)、焦点事件(3)、键盘事件(4)、文本事件 3. 事件对象(1)、获取事件对象(2)、事件对象常用属性 4. 环境对象 this5. 回调函数 二、 DOM事件进阶1. 事件流(1)、 捕获阶段(2)、 冒泡阶段(3)、 阻止冒泡(4) 、阻止元素默…

Optuna发布 4.0 重大更新:多目标TPESampler自动化超参数优化速度提升显著

Optuna这个备受欢迎的超参数优化框架在近期发布了其第四个主要版本。自2018年首次亮相以来&#xff0c;Optuna不断发展&#xff0c;现已成为机器学习领域的重要工具。其用户社区持续壮大&#xff0c;目前已达到以下里程碑&#xff1a; 10,000 GitHub星标每月300万 下载量16,00…

静心是良性循环

我发现一个挺有意思的事&#xff1a; 花时间修炼自己的心&#xff0c;让自己静心&#xff0c;就愿意多花时间修炼&#xff0c;会更加静心&#xff0c;这样就良性循环了。难的是刚开始&#xff0c;心不静&#xff0c;没时间修炼&#xff0c;心静不下来&#xff0c;更没时间修炼&…