【JavaEE精炼宝库】多线程1(认识线程 | 创建线程 | Thread 类)

目录

一、认识线程

1.1 线程的概念:

1.2 为什么需要线程:

1.3 面试题.谈谈进程和线程的区别:

1.4 Java的线程和操作系统线程的关系:

二、创建线程

2.1 创建线程的5种写法:

2.1.1 写法1.继承 Thread 类:

2.1.2 写法2.实现 Runnable 接口:

2.1.3 写法3.继承 Thread 使用匿名内部类:

2.1.4 写法4.实现 Runnable 使用匿名内部类:

2.1.5 写法5.使用lambda(推荐写法):

2.2 run方法和start方法的区别:

2.3 多线程的优势:

三、Thread类及常见方法

3.1 Thread 的常见构造方法:

3.2 jconsole使用过程:

3.3 Thread的常见属性:

3.3.1 属性列表:

3.3.2 前后台线程的关系:


一、认识线程

1.1 线程的概念:

一个线程就是一个 "执行流" 。每个线程之间都可以按照顺序执行自己的代码。多个线程之间 "同时" 执行着多份代码。

1.2 为什么需要线程:

(1)首先经过多年的发展,“并发编程” 已成成为 “刚需”。

• 单核CPU的发展遇到了瓶颈.要想提高算力,就需要多核CPU.而并发编程能更充分利用多核CPU资源。

 • 有些任务场景需要 "等待IO",为了让等待IO的时间能够去做一些其他的工作,也需要用到并发编程。

(2)其次,虽然多进程也能实现并发编程,但是线程比进程更轻量。

• 创建线程比创建进程更快。

• 销毁线程比销毁进程更快。

• 调度线程比调度进程更快。

(3)最后线程虽然比进程轻量,但是人们还不满足,于是又有了 "线程池" (ThreadPool)和 "协程"  (Coroutine)。

本文章主要介绍多线程,有关线程池和协程的概念后续会单独再写文章解释。

1.3 面试题.谈谈进程和线程的区别:

主要有如下四点:

• 进程是包含线程的。每个进程至少有⼀个线程存在,即主线程。

• 进程和进程之间不共享内存空间。同⼀个进程的线程之间共享同⼀个内存空间。

• 进程是系统分配资源的最小单位,线程是系统调度的最小单位。

• 一个进程挂了一般不会影响到其他进程。但是一个线程挂了,可能把同进程内的其他线程一起带走(整个进程崩溃)。

1.4 Java的线程和操作系统线程的关系:

线程是操作系统中的概念。操作系统内核实现了线程这样的机制,并且对用户层提供了一些API供用户使用(例如Linux的pthread库)。

Java标准库中Thread类可以视为是对操作系统提供的API进行了进一步的抽象和封装。

二、创建线程

下面我会提供创建线程的常见的5中写法,希望友友们都要掌握。下面经常会用到run方法和start方法,关于它们的区别,大家可以先把这5中写法看完后,我在后面有写区别🤩🤩🤩。

2.1 创建线程的5种写法:

2.1.1 写法1.继承 Thread 类:

继承 Thread 来创建⼀个线程类。写法如下:

class MyThread extends Thread{@Overridepublic void run() {System.out.println("hello Thread");System.out.println("Thread end");}
}
public class demo1 {public static void main(String[] args) {Thread t = new MyThread();//向上转型t.start();//启动线程}
}

这里解释一下为什么不能直接直接创建一个Thread对象,而是要再写一个Thread的子类:这是因为我们要重写 run 方法,如果不重写,直接调用原生的,会达不到我们的预期,这显然不是我们想看到的。

运行结果:

2.1.2 写法2.实现 Runnable 接口:

• Runnable接口源码:

通过观察其源码我们不难发现这是一个 “函数式接口” ,所以我们后面有一种写法就会利用到lambda表达式,里面涉及到的一些 “变量捕获” 的知识如果友友忘了的话要记得复习呀。

这个相比于第一个写法的好处是:能够起到解耦合的作用,例如当前是通过多线程的方式执行的,未来也可以很方便改成基于线程池的方式执行,也可以改成基于虚拟线程的方式执行(改动成本比较小),而继承Thread的写法基本就只适用于多线程。具体写法如下:

class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("hello Thread");System.out.println("Thread end");}
}
public class demo2 {public static void main(String[] args) {Thread t = new Thread(new MyRunnable());t.start();}
}

运行结果: 

2.1.3 写法3.继承 Thread 使用匿名内部类:

这个写法的效果和 2.1 的写法效果没有任何区别,因为使用匿名内部类本来就是为了方便。具体写法如下:

public class demo3 {public static void main(String[] args) {Thread t = new Thread(){@Overridepublic void run() {System.out.println("hello Thread");System.out.println("Thread end");}};t.start();}
}

运行结果和前面一样就不贴了。

2.1.4 写法4.实现 Runnable 使用匿名内部类:

和写法2效果一样:

public class demo4 {public static void main(String[] args) {Thread t = new Thread(new MyRunnable(){@Overridepublic void run() {System.out.println("hello Thread");System.out.println("Thread end");}});t.start();}
}

2.1.5 写法5.使用lambda(推荐写法):

这个是比较推荐的写法,因为是 “函数式接口” 我们就可以使用lambda表达式来简化写法。具体写法如下:

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

 上述 5 种写法本质都是要把线程执行的任务内容表示出来,通过 Thread 的 start 来创建 / 启动系统中的线程。Thread 对象和操作系统内核中的线程是一一对应的关系。 

2.2 run方法和start方法的区别:

之前我们已经看到了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。

• 覆写 run 方法是提供给线程要做的事情的指令清单。

• 线程对象可以认为是把 李四、王五叫过来了。

• 而调用 start() 方法,就是喊⼀声:”行动起来!“,线程才真正独立去执行了。

总而言之:调用 start 方法,才真的在操作系统的底层创建出一个线程。

2.3 多线程的优势:

利用多线程在一些场合可以提高程序的运行速度。具体案例如下:

前置知识:

• 使用 System.nanoTime() 可以记录当前系统的 纳秒 级时间戳。

• serial 串行的完成一系列运算。concurrency 使用两个线程并行的完成同样的运算。

如果对串行和并行不了解的话可以前往:JavaEE前置知识 中查看并行与并发的区别。

public class ThreadAdvantage {// 多线程并不⼀定就能提⾼速度,可以观察,count 不同,实际的运⾏效果也是不同的private static final long count = 10_0000_0000;public static void main(String[] args) throws InterruptedException {// 使⽤并发⽅式concurrency();// 使⽤串⾏⽅式serial();}private static void concurrency() throws InterruptedException {long begin = System.nanoTime();// 利⽤⼀个线程计算 a 的值Thread thread = new Thread(new Runnable() {@Overridepublic void run() {int a = 0;for (long i = 0; i < count; i++) {a--;}}});thread.start();// 主线程内计算 b 的值int b = 0;for (long i = 0; i < count; i++) {b--;}// 等待 thread 线程运⾏结束thread.join();// 统计耗时long end = System.nanoTime();double ms = (end - begin) * 1.0 / 1000 / 1000;System.out.printf("并发: %f 毫秒%n", ms);}private static void serial() {// 全部在主线程内计算 a、b 的值long begin = System.nanoTime();int a = 0;for (long i = 0; i < count; i++) {a--;}int b = 0;for (long i = 0; i < count; i++) {b--;}long end = System.nanoTime();double ms = (end - begin) * 1.0 / 1000 / 1000;System.out.printf("串⾏: %f 毫秒%n", ms);}
}

案例结果如下:

可以看到速度快了两倍多。不使用多线程的并发就会出现 “一核有难,多核围观” 的现象。

三、Thread类及常见方法

Thread 类是 JVM 用来管理线程的一个类,换句话说,每个线程都有一个唯一的 Thread 对象与之关联。

用我们上面的例子来看,每个执行流,也需要有一个对象来描述,类似下图所示,而 Thread 类的对象就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

3.1 Thread 的常见构造方法:

我们最常使用的是第三个,至于第五个目前在实际开发中更多的是被线程池取代了,这里只演示第三个。演示如下:

public class demo6 {public static void main(String[] args) {Thread t = new Thread(()->{while(true){System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}},"我的Thread");t.start();while(true){System.out.println("hello Main");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

我们可以利用使用 jconsole 命令观察线程。

3.2 jconsole使用过程:

我们利用上面的程序来进行连接,连接的时候要保证程序在运行中。

• 打开 c 盘并进入 Program Files :

• 进入 Java 中的 jdk :

• 进入 bin 后找到 jconsole 后以管理员的身份运行它:

•  看到这个就成功找到 jconsole 了:

记得连接我们运行的java程序。

注意:程序一定要保证在运行状态,比如我们写一个while(true)循环来保证我们连接的时候程序在跑,不然我们是连接不到的。

• 查看结果:

点击线程,在下面我们能看到main和我的Thread(修改命名)。

完成上面步骤我们已经成功利用 jconsole 查看运行的 java 线程。

3.3 Thread的常见属性:

3.3.1 属性列表:

属性解释:

• ID 是线程的唯一标识,不同线程不会重复。

• 名称是各种调试工具用到。

• 状态表示线程当前所处的一个情况。

• 优先级高的线程理论上来说更容易被调度到。

• 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。

• 是否存活,即简单的理解,为 run 方法是否运行结束了。

• 线程的中断问题,下面会单独讲。

3.3.2 前后台线程的关系:

• 前台线程:前台线程如果不运行结束的话,此时 Java 进程是一定不会结束的。

• 后台线程:后台线程即使继续在执行,也不能阻止 Java 进程结束。

我们默认创建的线程都是前台线程。我们可以利用 setDaemon 方法来把线程设置为后台线程。

注意:关于线程的各种属性的设置,都要放在 start 之前,一旦线程已经启动了,那么开弓就没有回头箭,这个时候再设置就来不及了,还会返回一个异常。

测试案例:

public class demo7 {public static void main(String[] args) {Thread t = new Thread(()->{while(true){System.out.println("hello Thread");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.setDaemon(true);//把t设置为后台线程t.start();//启动线程try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("Main end");}
}

友友们可以把这个代码贴到自己的编译器上面,看看有没有 setDaemon 的区别。

案例效果如下:

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

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

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

相关文章

简单的表单初始密码验证的实现

目录 简单示例&#xff1a;表单初始密码验证 1.1准备工作(图1&#xff09; 1.2 index部分 1.3 css部分 1.3.1先把css部分链接到index.html中&#xff0c;注意链接的地址。 1.3.2添加样式 1.4 JS部分 1.4.1 先把js部分链接到index.html中&am…

大华智能物联综合管理平台 fastjson远程代码执行漏洞复现

0x01 产品简介 大华ICC智能物联综合管理平台对技术组件进行模块化和松耦合,将解决方案分层分级,提高面向智慧物联的数据接入与生态合作能力。 0x02 漏洞概述 由于大华智能物联综合管理平台使用了存在漏洞的FastJson组件,未经身份验证的攻击者可利用 /evo-runs/v1.0/auths/…

块元素、内联元素、行内块元素

一、介绍&#xff1a; CSS元素划分成块元素、行内元素&#xff08;内联元素&#xff09;、行内块元素等多种常用类型。也就是说&#xff1a;在CSS中&#xff0c;元素根据其在页面上的布局方式被分为不同的显示类型。 背景&#xff1a;HTML负责定义网页的结构和内容&#xff0c…

如何利用AI实现文档处理自动化

文件处理在许多企业及员工看来是一项必不可少、却又耗时费力的工作。每天&#xff0c;他们往往需要花费无数个小时去对文件进行分类、归档、以及搜索。不过&#xff0c;如今人工智能&#xff08;AI&#xff09;正在以自动化的方式改变着这些琐碎的工作。 通过利用人工智能&…

H5 云商城 file.php 文件上传致RCE漏洞复现

0x01 产品简介 H5 云商城是一个基于 H5 技术的电子商务平台,旨在为用户提供方便快捷的在线购物体验。多平台适配:H5 云商城采用 H5 技术开发,具有良好的跨平台适配性。无论是在电脑、手机还是平板等设备上,用户都可以通过网页浏览器访问和使用云商城,无需安装额外的应用程…

在做题中学习(56):二维前缀和模板

【模板】二维前缀和_牛客题霸_牛客网 (nowcoder.com) 理解题意&#xff1a; 要求的是(x1,y1) - (x2,y2)这段区间的和。 解法&#xff1a;二维前缀和 1. 和一维前缀和一样&#xff0c;需要有一个同等规模的dp数组&#xff0c;用来保存一段连续区域的和。 在二维dp中&#xff0…

uni-app(三):离线打包与插件引用(Android)

离线打包与插件引用 1.下载Android离线SDK2.使用Android Studio打开离线打包项目并更新Gradle3.解决报错4.构建5.配置AppKeya.查看证书b.申请AppKeyc.配置AppKey 6.生成本地打包App资源7.拷贝App资源到Android项目中8.修改 appid9.修改Android项目配置文件10.下载证书并配置11.…

完美解决Windows10下-更换JDK环境变量后,在cmd下执行仍java -version然出现原来版本的JDK的问题

一、错误场景预演 本人欲将 JDK 1.8 通过安装包的方式升级为 JDK 22。 本地旧版本&#xff1a;1.8.0_221预升级版本&#xff1a;22.0.1 1.1、查看本地旧版本 在配置环境变量之前&#xff0c;首先我们要明确&#xff0c;本地存在旧版本&#xff0c;如果本地没有 Java&#x…

雷森托尔环保科技有限公司见证2024杭州数字供应链装备展潮流

参展企业介绍 青岛雷森托尔环保科技有限公司创建于2018年&#xff0c;位于山东青岛&#xff0c;现注册资本3000万。公司主营生产模压木托盘、化工木托盘、大型设备木包装、出口木托盘、酒柜木酒架等&#xff0c;公司拥有技术人员6人&#xff0c;均为包装设计专业毕业&#xff0…

云南区块链商户平台:抓包技术自制开票工具(二)

前言 上节我们分析了云南区块链商户平台的登录接口以及数据加密、解密&#xff0c;本节我们将构建一个项目框架&#xff0c;将大致的雏形制作出来 说明 由于我们使用开票软件都是在 云南区块链商户平台上操作&#xff0c;如果再开发电脑端就显得没必要&#xff0c;思考良久&…

架构每日一学 4:成为首席架构师,你必须学会顺应人性

本文首发于公众平台&#xff1a;腐烂的橘子 架构师生存法则之二&#xff1a;架构活动需要顺应人性 程序员入行的第一天起就进入了一个机器的世界。在别人的眼中&#xff0c;程序员平时很少说话&#xff0c;更多的时间在和电脑打交道。 程序员工作时间久了大脑会被格式化&…

HTML5 + CSS3实现卖茶女与水果男的巅峰微信聊天对决,看完后笑一整天

记得之前看过一段卖茶女与水果男的聊天视频&#xff0c;当时觉得真有意思&#xff0c;竟然还可以这样热爱自己的事业。我就想&#xff0c;用HTML5 CSS3实现一下这个过程&#xff0c;锻炼了技术&#xff0c;也娱乐了开发人员&#xff0c;多有意思的一件事啊。 目录 1 实现思路…

Android Studio连接MySQL8.0

【序言】 移动平台这个课程要做一个app的课设&#xff0c;我打算后期增加功能改成毕设&#xff0c;就想要使用MySQL来作为数据库&#xff0c;相对于SQLlite来说&#xff0c;我更熟悉MySQL一点。 【遇到的问题】 一直无法连接上数据库&#xff0c;开始的时候查了很多资料&#…

【通义千问系列】Qwen-Agent 从入门到精通【持续更新中……】

目录 前言一、快速开始1-1、介绍1-2、安装1-3、开发你自己的Agent 二、Qwen-Agent的使用和开发过程2-1、Agent2-1-1、Agent使用2-1-2、Agent开发 2-2、Tool2-2-1、工具使用2-2-2、工具开发 2-3、LLM2-3-1、LLM使用2-3-2、LLM开发 三、基于Qwen-Agent的案例分析3-1、3-2、 总结 …

拥有蝴蝶效应的爬虫如何进行防护

美国气象学家爱德华罗伦兹&#xff08;Edward N.Lorenz&#xff09;1963年在一篇提交纽约科学院的论文中分析了一个叫做蝴蝶效应的理论&#xff1a;“一个气象学家提及&#xff0c;如果这个理论被证明正确&#xff0c;一只海鸥扇动翅膀足以永远改变天气变化。”在以后的演讲和论…

小程序开发平台源码系统 低成本助力中小企业建站 带完整的安装代码包以及搭建教程

在当今数字化时代&#xff0c;拥有一个功能齐全、界面美观的小程序对于中小企业来说至关重要。然而&#xff0c;高昂的开发成本和复杂的搭建流程往往成为制约中小企业建立小程序的瓶颈。小编给大家分享一款低成本、易用性强的小程序开发平台源码系统&#xff0c;旨在助力中小企…

Python-VBA函数之旅-sorted函数

目录 一、sorted函数的常见应用场景 二、sorted函数使用注意事项 三、如何用好sorted函数&#xff1f; 1、sorted函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://blog.csdn.net/ygb_1024?spm1…

Python计算器程序代码

from tkinter import * import random class App: def __init__(self, master): self.master master self.initwidgets() #表达式的值 self.expr None def initwidgets(self): #定义一个输入组件 self.show Label(relief SUNKEN, font (Courier New, 24), width 25, bg …

一个“彩光”的自白:入室10万间的变革路

从0到10W 锐捷以太彩光的每一步 2021年 以太全光奠基 锐捷网络创新性提出了以太全光路线的代表性方案——极简以太全光解决方案1.0,在采用光纤作为传播介质的基础上,将交换机直接下沉至房间内。这一举措不仅简化了布线,新增业务只需在房间内灵活扩展,即可完成终端入网,而且通…

Leetcode—946. 验证栈序列【中等】

2024每日刷题&#xff08;133&#xff09; Leetcode—946. 验证栈序列 实现代码 class Solution { public:bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {int left 0;for(int i 0; i < popped.size(); i) {while(left &…