JUC并发编程进阶1:线程基础知识复习

1 从start一个线程说起

在 Java 中,Thread 类是用于创建和管理线程的核心类。通过调用 Thread 类的 start() 方法,可以启动一个新的线程,并执行线程的 run() 方法。下面我们来详细分析一下 start() 方法的实现。

1.1 代码示例

首先,我们来看一个简单的示例,如何通过 Thread 类启动一个线程:

public class ThreadBaseDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            // 线程执行的代码
            System.out.println("Thread t1 is running");
        }, "t1");
        t1.start();
    }
}

在这个示例中,我们创建了一个名为 t1 的线程,并通过 start() 方法启动它。线程启动后,会执行 run() 方法中的代码。

1.2 start() 方法的源码分析

接下来,我们来看看 start() 方法的源码:

public synchronized void start() {
    // 检查线程状态,如果线程已经被启动过,则抛出异常
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    // 将线程添加到当前线程的线程组中
    group.add(this);

    boolean started = false;
    try {
        // 调用 native 方法 start0() 启动线程
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                // 如果线程启动失败,从线程组中移除
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            // 忽略异常
        }
    }
}

1.2.1 线程状态检查

start() 方法首先检查 threadStatus 的值。threadStatus 是一个内部状态变量,用于表示线程的状态。如果 threadStatus 不等于 0,说明线程已经被启动过或已经结束,此时再次调用 start() 方法会抛出 IllegalThreadStateException 异常。

1.2.2 线程组管理

group.add(this) 将当前线程添加到当前线程的线程组中。线程组是一种管理线程的机制,可以将多个线程组织在一起进行统一管理。

1.2.3 启动线程

start0() 是一个 native 方法,由 C++ 实现。这个方法负责实际的线程启动工作。start0() 方法会创建一个新的操作系统线程,并调用线程的 run() 方法。

1.2.4 异常处理

finally 块中,如果线程启动失败(即 startedfalse),则会将线程从线程组中移除。如果移除过程中发生异常,则忽略该异常。

1.3 start0() 方法

start0() 方法是一个 native 方法,它的实现是由 C++ 编写的。这个方法负责与操作系统的线程管理机制进行交互,创建一个新的操作系统线程,并将其与 Java 线程关联起来。

private native void start0();

start0() 方法的具体实现依赖于底层的操作系统,不同的操作系统可能有不同的实现方式。例如,在 Linux 系统上,start0() 可能会调用 pthread_create 函数来创建一个新的线程。

1.4 小结

通过 Thread 类的 start() 方法,我们可以启动一个新的线程。start() 方法首先检查线程的状态,然后将线程添加到线程组中,最后调用 start0() 方法启动线程。start0() 是一个 native 方法,由 C++ 实现,负责实际的线程创建和启动工作。

2 Java多线程相关概念

  • 1把锁

    • synchronized(后面细讲)
  • 2个并

    • 并发:是在同一实体上的多个事件,是在一台处理器上“同时"处理多个任务,同一时刻,其实是只有一个事件在发生

    • 并行:是在不同实体上的多个事件,是在多台处理器上同时处理多个任务,同一时刻,大家真的都在做事情,你做你的,我做我的,但是我们都在做

  • 3个程

    • 进程: 简单的说,在系统中运行的一个应用程序就是一个进程,每一个进程都有它自己的内存空间和系统资源

    • 线程:也被称为轻量级进程,在同一个进程内会有1个或多个线程,是大多数操作系统进行时序调度的基本单元

    • 管程:Monitor(监视器),也就是我们平时所说的锁。Monitor其实是一种同步机制,它的义务是保证(同一时间)只有一个线程可以访问被保护的数据和代码,JVM中同步是基于进入和退出监视器(Monitor管程对象)来实现的,每个对象实例都会有一个Monitor对象,Monitor对象和Java对象一同创建并销毁,底层由C++语言实现

3 用户线程和守护线程

在 Java 中,线程分为用户线程(User Thread)和守护线程(Daemon Thread)。

3.1 用户线程(User Thread)

用户线程是系统的工作线程,它们负责完成程序需要完成的业务操作。默认情况下,创建的线程都是用户线程。用户线程的生命周期通常与程序的生命周期一致,即只要用户线程还在运行,程序就不会退出。

3.2 守护线程(Daemon Thread)

守护线程是一种特殊的线程,它们为其他线程提供服务,通常在后台默默地完成一些系统性的任务,比如垃圾回收线程。守护线程的生命周期与用户线程不同,如果所有的用户线程都结束了,守护线程也会随着 JVM 一同结束工作。换句话说,如果只剩下守护线程,JVM 会自动退出。

3.3 线程的 daemon 属性

每个线程都有一个 daemon 属性,用于判断该线程是用户线程还是守护线程。如果 daemon 属性为 true,则该线程为守护线程;如果为 false,则该线程为用户线程。

public final boolean isDaemon() {
    return daemon;
}

3.4 代码演示

下面是一个简单的代码示例,演示如何创建和使用守护线程:

public class DaemonDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"\t 开始运行, " +
                    (Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
            while (true){

            }
        }, "t1");
        t1.setDaemon(true);//通过设置属性Daemon来设置当前线程是否为守护线程

        t1.start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Thread.currentThread().getName()+"\t ----end 主线程");
    }
}
public class DaemonDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+"\t 开始运行, " +
                    (Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
            while (true){

            }
        }, "t1");
        t1.setDaemon(true);

        t1.start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Thread.currentThread().getName()+"\t ----end 主线程");
    }
}

  • 运行结果
输出:t1 开始运行,守护线程
main 主线程结束
  • 在main主线程结束后,守护线程会伴随着JVM一同结束工作,即使还有循环没有结束

3.5 小结

  • 用户线程:负责完成程序的业务操作,只要用户线程还在运行,程序就不会退出。
  • 守护线程:为其他线程提供服务,如果所有用户线程都结束了,守护线程会随着 JVM 一同结束工作。
  • setDaemon(true) 方法:必须在 start() 方法之前调用,否则会抛出 IllegalThreadStateException 异常。

4 思维导图

在这里插入图片描述

5 参考链接

【尚硅谷JUC并发编程(对标阿里P6-P7)】

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端开发笔记--html 黑马程序员1

文章目录 前端开发工具--VsCode前端开发基础语法VsCode优秀插件Chinese --中文插件Auto Rename Tag --自动重命名插件open in browserOpen in Default BrowserOpen in Other Browser Live Server -- 实时预览 前端开发工具–VsCode 轻量级与快速启动 快速加载:VSCo…

大数据毕业设计选题推荐-音乐数据分析系统-音乐推荐系统-Python数据可视化-Hive-Hadoop-Spark

✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

ansible自动化运维,一些基础命令、更方便掌握ansible。

1.先准备三台机子,一台ansible服务端、和两台客户端,配置客户端主机名、cinder和compute。 192.168.10.202ansible客户端192.168.10.56cinder客户端192.168.10.55compute客户端 2.下载ansible(客户端),准备repo文件。 #编写文件…

“网络安全等级保护测评入门:基础概念与重要性“

网络安全等级保护测评(简称“等保测评”)是依据国家网络安全等级保护制度,对信息系统安全等级进行评估和评定的过程。它是提高信息系统安全性、保障信息安全的重要手段。以下是关于等保测评的基础概念与重要性的详细解读: 一、等…

在docker的容器内如何查看Ubuntu系统版本

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境: docker 一、问题描述 由于 lsb_release -a 只能查看自己电脑(宿主机)的系统版本,如果在docker的容器内又应该如何查看Ubuntu系统版本呢&#xff…

IDEA运行Java程序时出错。提示:命令行过长。通过 JAR 清单或通过类路径文件缩短命令行,然后重新运行。

文章目录 一、遇到问题二、分析问题三、解决办法 一、遇到问题 运行 OpenCVUtils.test 时出错。命令行过长。 通过 JAR 清单或通过类路径文件缩短命令行,然后重新运行。二、分析问题 IDEA提示很明显了。 三、解决办法 运行——>编辑配置 运行/调试配置——&g…

欧科云链研究院深掘链上数据:洞察未来Web3的隐秘价值

目前链上数据正处于迈向下一个爆发的重要时刻。 随着Web3行业发展,公链数量呈现爆发式的增长,链上积聚的财富效应,特别是由行业热点话题引领的链上交互行为爆发式增长带来了巨量的链上数据,这些数据构筑了一个行为透明但与物理世…

模型 知识诅咒

系列文章 分享 模型,了解更多👉 模型_思维模型目录。知者难悟无知惑。 1 知识诅咒案例 1.1 会议室的误解 李经理是一家科技公司的产品经理,他负责领导一个新产品的开发项目。项目团队由不同背景和经验的成员组成,包括新入职的员…

kibana 删除es指定数据,不是删除索引

1 查询条件查询出满足条件的数据 GET /order_header_idx_202410/_search {"from":0,"size":10,"query":{"bool":{"filter":[{"term":{"oh_tenantId":{"value":"0211000001",&…

GitHub简介与安装使用入门教程

1、Git与GitHub的简介 Git是目前世界上最先进的分布式控制系统,它允许开发者跟踪和管理源代码的改动历史记录等,可以将你的代码恢复到某一个版本,支持多人协作开发。它的核心功能包括版本控制、分支管理、合并和冲突解决等,其操作…

JavaWeb概述及HTML | JavaWeb系列教程 | 第一期 | 前端

🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 今天毛毛张分享的是JavaWeb系列笔记第一期:JavaWeb概述及HTML语法 特别说明:本系列教程的整理全部来源于尚硅谷的JavaWeb课程笔记&#xff0c…

基于Python Django的在线考试管理系统

🍊作者:计算机毕设匠心工作室 🍊简介:毕业后就一直专业从事计算机软件程序开发,至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长:按照需求定制化开发项目…

硬件开发笔记(三十一):TPS54331电源设计(四):PCB布板12V转5V电路、12V转3.0V和12V转4V电路

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/142757509 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…

使用通义千问模拟ChatGPT-o1进行思考,并以类似于ChatGPT-o1的形式输出

prompt 你是ChatGPT O1,旨在通过第一性原理思维和基于证据的推理来解决用户问题。你的目标是提供清晰、循序渐进的解决方案、基础概念,并从头开始构建答案。 ### 指导原则: 以下是为大模型采用这种方法而设计的系统提示: 1. 理解…

HarmonyOS NEXT 应用开发实战(三、ArkUI页面底部导航TabBar的实现)

在开发HarmonyOS NEXT应用时,TabBar是用户界面设计中不可或缺的一部分。本文将通过代码示例,带领大家一同实现一个常用的TabBar,涵盖三个主要的内容页:首页、知乎日报和我的页面。以模仿知乎日报的项目为背景驱动,设定…

JavaScript reduce() 函数原理及应用

一. 引言 在 JavaScript 开发中,我们经常需要对数组中的元素进行统计、计算或转换,以便得到我们需要的结果。在这个过程中,reduce() 函数成为了一个非常有用的工具。reduce() 函数让我们能够以一种简洁而优雅的方式对数组中的元素进行累积计…

FFMpeg源码分析,关键结构体分析(一)

http://lazybing.github.io/blog/categories/ffmpegyuan-ma-fen-xi/ 一、下载FFmpeg的编译源码 进入网站:http://ffmpeg.org/download.html二、编译源码 执行下述命令: ./configure --prefix/usr/local/ffmpeg --enable-debug3 --enable-ffplay sudo …

Redis主从复制机制详解

目录 一、主从复制介绍二、搭建主从复制三、主从复制流程四、关于Replication ID五、主从复制核心知识六、主从复制应用场景七、主从复制的注意事项八、读写分离实战 一、主从复制介绍 1、什么是主从复制? 2、为什么要使用主从复制? redis-server单点…

谷歌浏览器 文件下载提示网络错误

情况描述: 谷歌版本:129.0.6668.90 (正式版本) (64 位) (cohort: Control)其他浏览器,比如火狐没有问题,但是谷歌会下载失败,故推断为谷歌浏览器导致的问题小文件比如1、2M会成功,大…

【问题分析】使用gperftools分析排查内存问题

背景 当程序长时间允许时(压测、服务器程序),就会面临更大的挑战,其中内存泄漏就是一类典型的问题,内存泄漏往往不易发现,导致的现象更是千奇百怪,本文主要介绍如何借助gperftools分析一个模块的内存泄漏 案例代码 …