java如何创建线程
java如何创建线程
- 1. java如何创建线程
- 1.1 通过继承Thread类来创建线程
- 1.2 通过实现Runnable接口来创建线程
- 1.3 通过匿名内部类来创建线程
- 1.4 lambda表达式
- 1.5 通过实现Runnable接口的方式创建线程目标类的优缺点
1. java如何创建线程
一个线程在Java中使用一个Thread实例来描述。Thread类是Java语言的一个重要的基础类,位于java.lang包中。Thread类有不少非常重要的属性和方法,用于存储和操作线程的描述信息.
Thread类的构造方法:

1.1 通过继承Thread类来创建线程
666
666
666
666
(1) 继承Thread类,创建一个新的线程类。
(2) 同时重写run()方法,将需要并发执行的业务代码编写在run()方法中。
代码写法如下:
class MyThread extends Thread {
//注释这个方法重写了父类方法@Overridepublic void run() {//需要并发执行的代码System.out.println("hello t");}
}
public class ThreadDemo1 {//第一种写法是使用Thread的run描述线程入口public static void main(String[] args) {Thread t = new MyThread();//向上转型t.start();//会创建新的线程System.out.println("hello main");}
}
此时我们可以运行一下:

此时呢~
我们就通过start()创建了一个新的线程,并且由于我们调用了start(),所以系统自动帮我们调用了run(),此时的run()是执行在 t 线程里面的.
我们可以通过打开jconsole.exe 这个文件来查看我们java在执行期间运行的线程.
由于线程执行完就会结束,为了方便查看,我们写一个死循环来方便我们观看.


此时,红色框框里面的main线程就是我们的主线程,另一个Thread-0就是我们刚才创建的一个 t 线程,由于我们没有指定名字,所以这个线程名字默认从0往后递增~

红色框框里面的两个构造方法是可以修改这个线程的名字的,先讲第一个红色框框里面的.
我们先在MyThread这个类中,通过快速创建构造方法,将可以传入名字参数的构造方法写出来.

class MyThread extends Thread {//调用父类的构造方法public MyThread(String name) {super(name);}@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello t");}}
}
此时呢?我们就可以对这个线程起名字了.

1.2 通过实现Runnable接口来创建线程
写一个类MyRunnable实现Runnable接口,覆写run()方法,创建MyRunnable对象runnable,将runnable作为参数调用Thread有参构造,创建线程thread,调用start()启动线程。
我们先查看一下Runnable这个接口.

Runnable有且仅有一个抽象方法 —— void run(),代表被执行的用户业务逻辑的抽象,在使用的时候,将用户业务逻辑编写在Runnable实现类的run()方法中。当Runnable实例传入Thread实例的target属性后,Runnable接口的run()的方法将被异步调用。
如何理解上面这句话呢?
我们先理解第一句话: 将用户业务逻辑编写在Runnable实现类的run()方法中.

由于我们的MyThread这个类实现了Runnable这个接口,所以我们需要重写这个接口里面的run()方法.如上图.
我们再来理解第二句话: 当Runnable实例传入Thread实例的target属性后,Runnable接口的run()的方法将被异步调用。
首先呢?我们需要new一个Runnable的实例.
MyRunnable myRunnable = new MyRunnable();
接着又讲到将Runnable的实例传入到Thread实例的target属性.
target是什么?
在Thread类的run()方法中,如果target(执行目标)不为空,就执行target属性的run()方法。而target属性是Thread类的一个实例属性,并且target属性的类型为Runnable。

此时我们的MyRunable的类型就是target的类型(Runnable),所以此时我们实例的 myrunable 就可以作为参数传入到Thread的构造方法中.
class MyRunnable implements Runnable {@Overridepublic void run() {while (true){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello t");}}
}
public class ThreadDemo2 {//第二种方法是使用Runnable interface(接口) 来描述线程入口public static void main(String[] args) {//先实例化一个实现Runnable接口的类MyRunnable myRunnable = new MyRunnable();//将这个类的引用作为参数传入Thread的构造方法中Thread t = new Thread(myRunnable);//此时可以通过start()创建一个线程,在这个线程中调用这个MyRunnable这个类中的run()方法.t.start();while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello main");}}
}
当我们运行时:

当然,我们也可以自己指定线程名字,这里就不进行演示了.
1.3 通过匿名内部类来创建线程
因为有些线程是只需要调用一次的,所以我们可以通过匿名内部类这样的方式来进行run()的重写.
代码如下:

在实例化这个对象时,在其后面写入一个{},此时就可以在这个{}中写入自己需要的方法.
注意:此时这个类是一次性的类.
上述代码的运行结果是:

可能有人就会问了,你这次怎么没有main线程啊,其实是因为main线程在执行完t.start()之后后续就没有代码需要执行了,所以自然这个线程就结束了,于是就是我们上述看到的,只有 t 线程.
在实现Runnable编写target执行目标类时,如果target实现类是一次性类,可以使用匿名实例的形式。
public class ThreadDemo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {while (true) {System.out.println("hello t");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}});t.start();while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello main");}}
}
1.4 lambda表达式
使用Lambda表达式优雅地创建Runnable线程目标类

我们通过观察这个Runnable接口可以发现,上面有一串注释,@FunctionalInterface 这个注释的意思就是标记这个接口为函数式接口,在Java中,“函数式接口”是有且仅有一个抽象方法的接口。反过来说,如果一个接口中包含两个或两个以上的抽象方法,就不能使用@FunctionalInterface注解,否则编译会报错。
Runnable接口是一个函数式接口,在接口实现时可以使用Lambda表达式提供匿名实现,编写出比较优雅的代码。 如果一个接口中有多个抽象方法,那样没有办法使用Lambda表达式简化。
public static void main(String[] args) {//()里面放参数,{}里面放函数体Thread t = new Thread(()->{while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello t");}},"猪猪侠");t.start();while (true) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("hello main");}}
但是呢? 此时小鱼有一个问题问大家,大家对比五段代码,找到哪几个有错误并且说明错误原因.
public class ThreadDemo5 {
//例一static int count = 0;public static void main(String[] args) {Thread t = new Thread(()->{while (true){System.out.println(count);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}
}
public class ThreadDemo5 {//例二public static void main(String[] args) {int count = 0 ;Thread t = new Thread(()->{while (true){System.out.println(count);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});count = 5;t.start();}
}
public class ThreadDemo5 {//例三public static void main(String[] args) {int count = 0 ;Thread t = new Thread(()->{while (true){System.out.println(count);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}
}
public class ThreadDemo5 {//例四public static void main(String[] args) {final int count = 0 ;Thread t = new Thread(()->{while (true){System.out.println(count);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}
}
public class ThreadDemo5 {//例五public static void main(String[] args) {int count = 0 ;Thread t = new Thread(()->{while (true){System.out.println(count++);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}
}
(1) 第一个没有错误,由于count是成员变量,在线程中是共享资源,所以lambda表达式中是可以访问这个变量并且对其进行修改的.
(2) 第二个有错误,Lambda 表达式(匿名类) 不能访问非 final 的局部变量 .
因为成员变量存在堆中,而局部变量是在栈上分配,存在于虚拟机栈的局部变量表中,Lambda 表达(匿名类) 有可能会在另一个线程中执行。如果在线程中要直接访问一个局部变量,可能线程执行时该局部变量已经被销毁了,而 final 类型的局部变量在 Lambda 表达式(匿名类) 中其实是局部变量的一个拷贝
(3) 第三个没有错误,虽然我们的count是局部变量,但是由于我们的代码并未有对该变量进行后续的修改,我们可以称这个count变量为实际final,意思就是虽然没有被final修饰,但是由于并没有修改这个变量的值,所以在lambda表达式中可以使用.
(4) 没有问题
(5) 错误,lambda表达式不能修改局部变量.原因如下:
lambda表达式不能修改局部变量
1.5 通过实现Runnable接口的方式创建线程目标类的优缺点
通过实现Runnable接口的方式创建线程目标类有以下缺点:
- 所创建的类并不是线程类,而是线程的target执行目标类,需要将其实例作为参数传入线程类的构造器,才能创建真正的线程。
- 如果访问当前线程的属性,不能直接访问Thread的实例方法,必须通过Thread.currentThread()获取当前线程实例,才能访问和控制当前线程。
通过实现Runnable接口的方式创建线程目标类有以下优点:
- 可以避免由于Java单继承带来的局限性。如果异步逻辑所在类已经继承了一个基类,就没有办法再继承Thread类。比如,当一个Cat类继承了Animal类,再要继承Thread类就不行了。所以在已经存在继承关系的情况下,只能使用实现Runnable接口的方式。
- 逻辑和数据更好分离。通过实现Runnable接口的方法创建多线程更加适合同一个资源被多段业务逻辑并行处理的场景。在同一个资源被多个线程逻辑异步、并行处理的场景中,通过实现Runnable接口的方式设计多个target执行目标类可以更加方便、清晰地将执行逻辑和数据存储分离,更好地体现了面向对象的设计思想。
相关文章:
java如何创建线程
java如何创建线程1. java如何创建线程1.1 通过继承Thread类来创建线程1.2 通过实现Runnable接口来创建线程1.3 通过匿名内部类来创建线程1.4 lambda表达式1.5 通过实现Runnable接口的方式创建线程目标类的优缺点1. java如何创建线程 一个线程在Java中使用一个Thread实例来描述…...
要是早看到这篇文章,你起码少走3年弯路,20年老程序员的忠告
文章目录前言一、程序员的薪资是怎么样的?二、我现在的情况适合做程序员吗?三、大学期间到底应该学些什么?四、工作还是考研?五、总结前言 我是龙叔,一名工作了20多年的退休老程序员。 如果你在工作之前看到这篇文章…...
IP地址的分类
1. 前言 最初设计互联网络时,为了便于寻址以及层次化构造网络,每个IP地址包括两个标识码(ID),即网络ID和主机ID。 同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包括网络上工…...
win10下使用docker运行部署nginx,mysql
一、docker的步骤:1.进入docker官网下载安装包2.打开控制面板 - 程序和功能 - 启用或关闭Windows功能,勾选Hyper-V,然后点击确定即可,如图:3.重新启动电脑4.启动Docker在桌面找到Docker for Windows快捷方式࿰…...
sprinboot车辆充电桩
sprinboot车辆充电桩演示录像2022开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:ecli…...
仿京东放大镜效果的实现
仿京东放大镜 (1) 整个案例可以分为三个功能模块 (2) 鼠标经过小图片盒子, 黄色的遮挡层 和 大图片盒子显示,离开隐藏2个盒子功能 (3)黄色的遮挡层跟随鼠标功能。 (4&…...
ESP32设备驱动-LM35温度传感器驱动
LM35温度传感器驱动 文章目录 LM35温度传感器驱动1、LM35介绍2、硬件准备3、软件准备4、驱动实现1、LM35介绍 LM35 系列是精密集成电路温度传感器,其输出电压与摄氏(摄氏度)温度成线性比例。 因此,LM35 优于以开尔文校准的线性温度传感器,因为用户无需从其输出中减去较大…...
基于深度学习的犬种识别软件(YOLOv5清新界面版,Python代码)
摘要:基于深度学习的犬种识别软件用于识别常见多个犬品种,基于YOLOv5算法检测犬种,并通过界面显示记录和管理,智能辅助人们辨别犬种。本文详细介绍博主自主开发的犬种检测系统,在介绍算法原理的同时,给出Py…...
【IDEA插件开发】环境搭建
基础信息 GRADLE 7.5.1 IDEA IntelliJ IDEA 2020.1.1 (Ultimate Edition) Build #IU-201.7223.91, built on April 30, 2020 Licensed to https://zhile.io You have a perpetual fallback license for this version Subscription is active until July 8, 2089 Runtime ve…...
【蓝桥杯专题】 DP(C++ | 洛谷 | acwing | 蓝桥)
菜狗现在才开始备战蓝桥杯QAQ 文章目录【蓝桥杯专题】 DP(C | 洛谷 | acwing | 蓝桥)AcWing 1205. 买不到的数目Acwing 1216. 饮料换购【模拟】01背包271. 杨老师的照相排列最长公共上升子序列PPPPPPPP总结【蓝桥杯专题】 DP(C | 洛谷 | acwi…...
咪咕MGV3201_ZG_GK国科6323_UWE5621DS_免拆卡刷固件包
咪咕MGV3201_ZG_GK国科6323_UWE5621DS_免拆卡刷固件包 特点: 1、适用于对应型号的电视盒子刷机; 2、开放原厂固件屏蔽的市场安装和u盘安装apk; 3、修改dns,三网通用; 4、大量精简内置的没用的软件,运行…...
重构数据-Change Value to Reference将实值对象改为引用对象三
重构数据-Change Value to Reference将实值对象改为引用对象三 1.将实值对象改为引用对象 1.1.实值对象和引用对象区别 下面通过客户Customer和订单Order两个对象介绍下它们的区别 值对象:当一个客户Customer下了多个订单Order后,每个订单类都将创建一…...
计算机网络——通信专业面试问题学习笔记
文章目录1、计算机网络这门课学了什么?目录里有多少章?2、Internet的概念与发展史3、什么是交换?三种交换方式4、OSI的七层协议, TCP/IP的四层协议, 五层协议5、WAN 、LAN 、MAN、PAN这些能分的清楚吗?全称分别都是什么࿱…...
代码随想录算法训练营第三十天 | 332.重新安排行程 51. N皇后 37. 解数独 总结
打卡第30天,回溯算法第二刷。 今日任务 332.重新安排行程51.N皇后37.解数独总结 332.重新安排行程 给你一份航线列表 tickets ,其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从…...
Windows权限提升—MySQL数据库提权
Windows权限提升—MySQL数据库提权1. 前言2. 数据库提权介绍2.1. 常见数据库端口2.2. MySQL数据库提权条件2.3. MySQL数据库提权类型3. MySQL中UDF提权3.1. UDF提权介绍3.2. UDF提权思路3.3. UDF提权步骤3.3.1. 获取外连数据库3.3.1.1. 外连数据库3.3.1.2. 连接数据库3.3.1.3. …...
使用旧电脑玩Linux
今天给大家讲讲使用旧电脑玩Linux,大家应该都知道旧电脑的硬件一般比较落后,特别是一些非常老的电脑,目前还在使用的是机械硬盘,如是要跑windows可想而知,但是Linux系统对硬件性能的要求可比windows低的多了࿰…...
Linux安装EMQX(简洁版)
安装目录 mkdir /opt/emqx && cd /opt/emqx 安装包下载 yum -y install wget && wget https://www.emqx.com/zh/downloads/broker/5.0.20/emqx-5.0.20-el7-amd64.tar.gz 注意:https://www.emqx.com/zh/downloads/broker获取下载链接并替换(后缀&…...
基于STM32 + FPGA 的软体机器人的 CAN总线运动控制器的设计
针对在软体机器人控制时,多电机协同控制过程中难度大、通用性差、协同性差等缺点,设计了基于 ARM和 FPGA的软体机器人的控制器局域网络 ( controller area network,CAN) 总线运动控制器,采用 ARMCortex-M4 …...
ROC曲线和AUC值
ROC曲线(Receiver Operating Characteristic,受试者工作特征)评价分类模型的可视化工具,是一条横纵坐标都限制在0-1范围内的曲线横坐标是假正率FPR,错误地判断为正例的概率纵坐标是真正率TPR,正确地判断为正…...
【vue.js】在网页中实现一个金属抛光质感的按钮
文章目录前言效果电脑效果手机效果说明完整代码index.html前言 诶?这有一个按钮(~ ̄▽ ̄)~,这是一个在html中实现的具有金属质感并且能镜面反射的按钮~ 效果 电脑效果 手机效果 说明 主要思路是使用 navig…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
全面解析数据库:从基础概念到前沿应用
在数字化时代,数据已成为企业和社会发展的核心资产,而数据库作为存储、管理和处理数据的关键工具,在各个领域发挥着举足轻重的作用。从电商平台的商品信息管理,到社交网络的用户数据存储,再到金融行业的交易记录处理&a…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
Java后端检查空条件查询
通过抛出运行异常:throw new RuntimeException("请输入查询条件!");BranchWarehouseServiceImpl.java // 查询试剂交易(入库/出库)记录Overridepublic List<BranchWarehouseTransactions> queryForReagent(Branch…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
Ray框架:分布式AI训练与调参实践
Ray框架:分布式AI训练与调参实践 系统化学习人工智能网站(收藏):https://www.captainbed.cn/flu 文章目录 Ray框架:分布式AI训练与调参实践摘要引言框架架构解析1. 核心组件设计2. 关键技术实现2.1 动态资源调度2.2 …...
【Vue】scoped+组件通信+props校验
【scoped作用及原理】 【作用】 默认写在组件中style的样式会全局生效, 因此很容易造成多个组件之间的样式冲突问题 故而可以给组件加上scoped 属性, 令样式只作用于当前组件的标签 作用:防止不同vue组件样式污染 【原理】 给组件加上scoped 属性后…...
【Linux】使用1Panel 面板让服务器定时自动执行任务
服务器就是一台24小时开机的主机,相比自己家中不定时开关机的主机更适合完成定时任务,例如下载资源、备份上传,或者登录某个网站执行一些操作,只需要编写 脚本,然后让服务器定时来执行这个脚本就可以。 有很多方法实现…...
