多线程基础

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

多线程向来是面试的重灾区,它真的很难。一般来说,普通的开发人员很少有机会能直接写多线程,一般都是使用封装好的工具类或者JDK提供的API,但并不意味着我们可以不用了解多线程。

学习多线程的好处至少有两点:

  • 应付面试
  • 深入理解并发编程,帮助我们更好地使用JDK提供的锁及JUC工具包

今天我们再来强化一下多线程的基础知识。

线程类与任务类

我在初学多线程时,也感到云里雾里,后来才发现自己一开始就把一些概念搞错了!很多博客或者视频每次都会说“实现”多线程的方式有3种:Thread、Runnable和Callable,其实我个人是不太认同这种说法的。Thread是线程类,另外两个是任务类,不是一类事物啊!

也即是说,JDK看似提供了很多和多线程相关的类,实际上有且仅有Thread类能通过start0()方法向操作系统申请线程资源(本地方法)。

线程池只是对Thread的复用,两者本质上可以归为一类,这里暂且不讨论

另外,JVM的线程和操作系统的线程是一一对应的,当我们new一个Thread对象并调用start()方法后,JVM的Thread对象就与系统底层的一个线程资源绑定了。

而Runnable和Callable并不会产生线程,仅仅用于包裹待执行的任务。如果没有线程或线程池去执行,它们只不过是一坨普通的代码。

为了让Thread和Runnable/Callable产生关联,通常需要我们手动进行“组合”(Thread只能接收Runnable,Callable要使用线程池,后面再介绍):

new Thread(() -> {// 把任务包裹在Runnable任务类中,通过构造参数传入ThreadSystem.out.println("待执行任务");
}).start();

但实际开发中,大家肯定也见过这种写法:

new Thread() {@Overridepublic void run() {// 直接重写Thread的run(),把待执行的任务放里面System.out.println("待执行任务");}
}.start();

注意,上面这种写法可不是传入Runnable/Callable,而是采用匿名类的方式重写了Thread自己的run()。

总结一下,要想让多线程执行一个任务,大致有以下几种做法:

  • 线程与任务不分离
    • 重写Thread的run(),把任务直接塞到Thread内部,执行路径是:JVM线程-->Thread#run()
  • 线程与任务分离(推荐)
    • 把任务塞到Runnable,丢入Thread里,执行路径是:JVM线程-->Thread#run()-->target.run()
    • 把任务塞到Runnable/Callable,丢到线程池里,屏蔽内部细节,省心省力

注意,当Thread#start()向操作系统申请线程后,线程的执行入口始终是Thread#run(),而不是Runnable/Callable的run()

到这里,我们替大家扫清了一些繁杂的概念,只需记住Java创建多线程有且仅有一种方式:Thread!无论是直接通过new Thread().start(),或是通过线程池,底层其实都是Thread在向操作系统申请资源,而且新线程启动后,会找到原来的Thread,从它的run()方法开始执行。

任务代码是如何被执行到的?

上面提到过,如果需要多线程帮我们执行任务,一般有3种方式:

  • 重写Thread#run()
  • 将任务包装成Runnable,丢入Thread
  • 将任务包装成Runnable/Callable,丢入线程池

那么,为什么我把代码放在这些指定的地方,线程就能执行到呢?

其实代码的执行顺序,说到底也是人为设计、编排的,只不过Thread、线程池等设计得更为精妙。整个过程就像一条流水线,从上游到下游,我们只要把商品放入指定的地方,最终就会被封口、打包并装箱。

这里主要介绍方式1、2的原理,线程池的执行原理后面会介绍。Thread是如何执行任务的呢?关键在于Thread#run():

Thread#start()的作用是向操作系统申请线程资源,当操作系统分配好线程资源,并且当前线程得到CPU执行权时,执行的入口一定是Thread#run()。

那么线程执行run()时,会发生什么呢?

  • 如果我们重写了Thread#run(),就会执行我们重写的方法(任务和线程不分离)
  • 如果我们没有重写Thread#run()
    • target为null,run()为空,直接结束
    • target不为null,就会执行target的run()。而target就是我们通过Thread构造器传入的Runnable对象

所以,如果不重写Thread#run(),就一定要传入任务类(target),否则新建的Thread无任务可执行,就浪费了

最后,再来回顾一下让线程执行指定任务的几种常见方式:

public class AsyncAndWaitTest {public static void main(String[] args) throws ExecutionException, InterruptedException {// 方式1:重写Thread#run()Thread thread = new Thread() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "========>正在执行");}};thread.start();// 方式2:构造方法传入Runnable实例new Thread(() -> {System.out.println(Thread.currentThread().getName() + "========>正在执行");}).start();// 方式3:线程池 + Callable/Runnable,这里以Callable为例ExecutorService executorService = Executors.newSingleThreadExecutor();Future<String> submit = executorService.submit(() -> {System.out.println(Thread.currentThread().getName() + "========>正在执行");Thread.sleep(3 * 1000L);return "success";});String result = submit.get();System.out.println("result=======>" + result);// 关闭线程池executorService.shutdown();}
}

除了上面3种利用多线程执行任务的方式,我们再另外介绍一种初学者可能觉得有点绕、但源码里经常会见到的写法,算是Runnable的变种写法

把new Thread().start()隐藏到某个类的内部

重点关注Worker到底是什么,以及begin()内部做了什么。不熟悉的同学不妨自己写一下,琢磨一下。我们马上会在JDK的某个类中看到类似的写法!

总之,在我心里Thread的Level要比Runnbale、Callable高一级。看到很多人把它们混在一起,不禁想起一句话:

萧某大好男儿,竟和你这种人齐名! --- 乔峰

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

进群,大家一起学习,一起进步,一起对抗互联网寒冬

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

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

相关文章

小中大女童穿搭 I 时尚百搭保暖性超赞

杜邦三防面料&#xff0b;超足充绒量 金属拉链&#xff0b;金属按扣&#xff0b;松紧下摆 可以说是将细节做到实处 防风保暖潮nice 经典宽松版型对身材包容性很强 后背和口袋两侧都做了 可调节抽绳&#xff0c;不会显得臃肿 很简单大方&#xff0c;搭配卫裤牛仔裤都好看…

推荐几款转换视频格式的好用转换工具,小白也能上手

视频格式转换工具是一种专门转换视频的软件&#xff0c;可让你将一种视频格式转换为另一种视频格式&#xff08;例如&#xff0c;MOV 到 MP4&#xff09;&#xff0c;通常可以节省空间。 本文将介绍一些用于转换视频格式的好用转换工具&#xff0c;并且详细描述了它们的主要功…

快速安装Axure RP Extension for Chrome插件

打开原型文件的html&#xff0c;会跳转到这个页面&#xff0c;怎么破&#xff1f; 我们点开产品设计的原型图如果没有下载Axure插件是打不开&#xff0c;而我们国内网通常又不能再google商店搜索对应插件&#xff0c;下面教大家如何快速安装 1、打开原型文件->resources-&g…

SQL Server 数据库,创建触发器避免数据被更改

5.4触发器 触发器是一种特殊类型的存储过程&#xff0c;当表中的数据发生更新时将自动调用&#xff0c;以响应INSERT、 UPDATE 或DELETE 语句。 5.4.1什么是触发器 1.触发器的概念 触发器是在对表进行插入、更新或删除操作时自动执行的存储过程&#xff0c;触发器通常用于强…

软件系统应用开发安全指南

2.1.应用系统架构安全设计要求 2.2.应用系统软件功能安全设计要求 2.3.应用系统存储安全设计要求 2.4.应用系统通讯安全设计要求 2.5.应用系统数据库安全设计要求 2.6.应用系统数据安全设计要求 全资料获取进主页。

微信小程序 -订阅发布模式

图形展示&#xff1a; 代码展示&#xff1a; 1. 安装模块 pubsub-js npm i pubsub-js --save 2. 导入模块&#xff08;在需要订阅发布的 js 页面内进行导入&#xff09; import PubSub from pubsub-js 注&#xff1a;在微信小程序中无法直接npm 下载 导入 的&#xff08;安…

会声会影2024编辑过程很卡怎么解决

会声会影是一款常用的视频剪辑软件&#xff0c;在使用过程中&#xff0c;可能会遇到视频卡顿的情况。造成这种情况的原因有很多&#xff0c;下面我就给大家讲解一下用会声会影做视频会卡的原因&#xff0c;会声会影剪辑时卡顿怎么设置的方法。 会声会影 2022 安装包:https://so…

思维模型 心理防御机制

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。用幻想保护自己。 1 心理防御机制的应用 1.1 以下是心理防御机制在人际关系中的应用 1 心理防御机制的正向使用 小明在一次重要的演讲中犯了一个错误&#xff0c;他感到非常尴尬和失落。…

vue+echarts实现桑吉图的效果

前言&#xff1a; 在我们项目使用图形的情况下&#xff0c;桑吉图算是冷门的图形了&#xff0c;但是它可以实现我们对多级数据之间数据流向更好的展示的需求&#xff0c;比如&#xff0c;我们实际数据流向中&#xff0c;具有1对多&#xff0c;多对多的情况下&#xff0c;如果用…

深入理解mysql的explain命令

1 基础 全网最全 | MySQL EXPLAIN 完全解读 1.1 MySQL中EXPLAIN命令提供的字段包括&#xff1a; id&#xff1a;查询的标识符。select_type&#xff1a;查询的类型&#xff08;如SIMPLE, PRIMARY, SUBQUERY等&#xff09;。table&#xff1a;查询的是哪个表。partitions&…

《Java 并发编程艺术》笔记(上)

如何减少上下文切换 减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。 无锁并发编程&#xff1a;多线程竞争锁时&#xff0c;会引起上下文切换&#xff0c;所以多线程处理数据时&#xff0c;可以用一些办法来避免使用锁。如将数据的 ID 按照 Hash 算法…

空对象指针为什么有时候能调用成员函数

在谈这个话题之前呢&#xff0c;还是得了解一下内存布局&#xff0c;以x86的32位系统为例&#xff1a; 然后得明确一点&#xff0c;NULL指针是无法访问的&#xff0c;如果强行访问&#xff0c;则会引发异常 然而空对象指针有时候却能够调用成员函数 class C { public:int a;st…

kali linux下可用的wine QQ/微信

kali linux下可以使用网页版本的 QQ/微信。但是体验差强人意&#xff0c;无法截图&#xff0c;无法发送word中的复制文字&#xff0c;反而能发送excel表格中的复制文字&#xff0c;无法拖拽发送等多种难以接受的体验。 所以尝试wine 版本&#xff0c;好处是通过交叉编译&#…

【linux系统编程】编辑器gcc/g++

目录 Linux下的编辑器 介绍&#xff1a; 1&#xff0c;编辑器gcc/g 1-1&#xff0c;系统的编译过程 1-2&#xff0c;预处理过程 1-3&#xff0c;编译过程 1-4&#xff0c;汇编过程 1-5&#xff0c;链接过程 Linux下的编辑器 介绍&#xff1a; Linux系统下可支持很多高…

Python读写txt文件数据

&#x1f388; 博主&#xff1a;一只程序猿子 &#x1f388; 博客主页&#xff1a;一只程序猿子 博客主页 &#x1f388; 个人介绍&#xff1a;爱好(bushi)编程&#xff01; &#x1f388; 创作不易&#xff1a;如喜欢麻烦您点个&#x1f44d;或者点个⭐&#xff01; &#x1f…

html和css写淘宝的快速导航条

目录 1、css代码 2、html代码 1、css代码 <style>* {margin: 0;padding: 0;list-style: none;text-decoration: none;}.nav {width: 900px;height: 40px;background-color: rgb(247, 249, 250);margin: 50px auto;padding-left: 30px;}.nav>li {float: left;width: 1…

云天励飞即将亮相“双数峰会”

第二届数字政府建设峰会暨数字湾区发展论坛即将在12月8-10日举办。本次“双数”峰会上&#xff0c;云天励飞将与CEC联合展示&#xff0c;重点展出大模型在数字政府领域的创新应用&#xff0c;以及云天励飞自主研发的大模型推理芯片。 “云天天书”包含通用大模型、行业大模型、…

Kali Linux 2023.4 已经发布了!

开发人员推出了 Kali Linux 2023.4&#xff0c;这是2023 年发行版的第四个也是最后一个版本。 新产品已经可供下载&#xff0c;包含15 个新工具和 GNOME 45。 Offective Security 团队报告称&#xff0c;在今年的最终版本中&#xff0c;操作系统中并没有添加太多新功能&…

用 C 写一个卷积神经网络

用 C 写一个卷积神经网络 深度学习领域最近发展很快&#xff0c;前一段时间读transformer论文《Attention Is All You Need》时&#xff0c;被一些神经网络和深度学习的概念搞得云里雾里&#xff0c;其实也根本没读懂。发现深度学习和传统的软件开发工程领域的差别挺大&#xf…

动态代理配置方法。如何使用代理IP保护隐私安全?

随着网络技术的不断发展&#xff0c;越来越多的人开始使用代理IP来保护自己的隐私安全。代理IP是一种通过代理服务器来访问网络的特殊技术&#xff0c;可以隐藏用户的真实IP地址&#xff0c;从而保护用户的隐私。本文将介绍动态代理的配置方法以及如何使用代理IP保护隐私安全。…