当前位置: 首页 > news >正文

Java线程 - 详解(1)

一,创建线程

方法一:继承Thread类

class MyThread extends Thread{@Overridepublic void run() {System.out.println("线程1");}
}public class Test {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();//start()方法启动线程//和上面的方法一样,只不过使用匿名内部类实现Thread thread1 = new Thread(){@Overridepublic void run() {System.out.println("线程2");}};thread1.start();}
}

方法二:实现Runnable接口

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程1");}
}
public class Test {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();//匿名内部类实现Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程2");}});thread2.start();//lambda表达式实现Thread thread3 = new Thread(() -> System.out.println("线程3"));thread3.start();}
}

二,Thread类及常见方法

2.1 构造方法

方法说明
Thread()创建线程对象
Thread(Runnable  target)使用Runnable对象创建线程对象
Thread(String  name)创建线程对象并命名
Thread(Runnable  target,String  name)使用Runnable对象创建线程对象,并命名
Thread(ThreadGroup  group,Runnable  target)线程可以被用来分组管理,分好的组即为线程组(了解即可)

2.2 获取 Thread 的常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID是线程的唯一标识,ID是JAVA分配的,不会出现重复的,与上篇博客中PCB结构中的pid不是同一个东西。
  • 名称是方便各种调试工具使用。
  • 后台线程不会影响线程的结束,前台线程会影响线程的结束,一般线程默认为前台线程,还有一个注意点——JVM会在一个进程的所有后台进程结束后,才会结束运行。
  • 是否存活,简单理解就是 run 方法是否运行结束。
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{System.out.println("线程开始");try {Thread.sleep(1000);//休眠线程 xxx ms} catch (InterruptedException e) {throw new RuntimeException(e);}},"1号线程");thread.setDaemon(true);//设置为后台线程thread.start();System.out.println(thread.getName() + " " + thread.isAlive());Thread.sleep(3000);System.out.println("线程结束");System.out.println(thread.isAlive());}
}

 

2.3 start()  与  run() 的区别

作用功能:

  1. start()方法内部是会调用系统的API,在系统内核创建一个线程
  2. run()方法只是描述线程具体实现的任务(会在start创建好之后会自动被调用)

运行结果:

  1. start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
  2. run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次

 2.4 中断一个线程

在Java中,终止/销毁一个线程的做法比较单一,就是尽快让 run 方法执行结束。

方法一: 在代码中手动创建一个标志位,来作为 run 的执行结束条件,比如在很多线程中,执行时间长往往是写了一个循环。

public class Demo {private static boolean isQuit = false;//通过类属性来控制public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (!isQuit){System.out.println("666");}});thread.start();Thread.sleep(1);isQuit = true;}
}

 注:这里的 isQuit 不能是局部变量,因为如果是局部变量就不满足 lambda表达式中的变量捕获语法。

但是上面的方法有两个缺点:1. 需要手动创建变量 2. 当线程内部在 sleep 的时候,主线程修改变量时,新线程内部不能及时响应,所以Java提供了另一种解决方法:

方法二:使用 interupt() 和 isInterrupted()

方法说明
public void interrupt()中断对象关联的线程,如果线程阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted()判断当前线程中的标志位是否设置,调用后清除标志位
public boolean isInterrupted()判断对象关联的线程的标志位是否设置,调用后不清除标志
public class Demo {public static void main(String[] args) {Thread thread = new Thread(()->{// Thread.currentThread()作用是得到当前的线程// isInterrupted() 判断标识符是否为false//或者 while(!Thread.interrupted()) 效果一样while(!Thread.currentThread().isInterrupted()){System.out.println("线程工作中!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//打印异常}}});thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();//将标识符设置为true}
}

但是报错后,该线程没有中断,而是继续执行,这是为什么呢?

这是因为当我们将 标识符设为true 时,正好线程在sleep,会触发sleep内部的一个异常,从而会将线程从sleep中唤醒,但是在sleep抛出异常的同时,它会自动删除刚才设置的 标志位,这将会使 interrupt 这一操作好像没有被执行。

为什么Java会这样设定呢? 因为 Java 是希望当 线程收到 "中断" 信号时,它能自由决定接下来要怎么处理,比如:我们可以在打印报错后 接着写一些代码 :

public class Demo {public static void main(String[] args) {Thread thread = new Thread(()->{// Thread.currentThread()作用是得到当前的线程// isInterrupted() 判断标识符是否为false//或者 while(!Thread.interrupted()) 效果一样while(!Thread.currentThread().isInterrupted()){System.out.println("线程工作中!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//打印异常System.out.println("还需要完成的操作...");//2.break;//1.直接退出}}});thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();//将标识符设置为true}
}

 注:

  1. 如果没有sleep,就不会出现上述情况,线程会直接退出!!!
  2. 我们不建议使用 Thread.interrupted() 这种做法,因为该方法是静态方法,意味着所有的线程共用一个标识符,而我们使用的线程肯定不止一个,如果使用该方法,就乱套了!!!

2.5 等待一个线程 - join()

作用:让一个线程等待另一个线程执行结束后,在继续执行。本质上是控制线程结束的顺序。

方法作用
public void join()等待线程结束
public void join(long millis)等待线程结束,但是最多等待 millis 毫秒
public void join(long millis, int nanos)同上,但是精度更高
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 5; i++) {System.out.println("线程工作中!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();System.out.println("main线程开始等待");thread.join();System.out.println("等待结束");}
}

 注:

  1. 要分清哪个线程是等待的,哪个线程是被等待的
  2. join() 会出现 "死等" 的情况,我们一般不会使用,建议使用有参数的,可以自定义等待时间

2.6 其他 

方法作用
public static Thread currentThread()返回当前线程对象的引用
public static void sleep(long millis) throws interruptedException当前线程休眠millis毫秒
public static void sleep(long millis, int nanos) throws interruptedException同上,精度更高

三,线程的状态

  •  NEW:  Thread 对象已经有了,start 方法还没有调用
  • TERMINATED:  Thread 对象还在,内核中的线程已经没了
  • RUNNABLE:  就绪状态 (线程已经在 CPU 上运行 / 线程正在排队等待去 CPU 上运行)
  • TIME_WAITING:  阻塞,由于 sleep 这种固定时间的方式产生阻塞
  • WAITING:  阻塞,由于 wait 这种不固定时间的方式产生阻塞
  • BLOCKED:  阻塞,由于锁竞争导致的阻塞
public class Demo2 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}});// getState() 获得当前线程的状态System.out.println(thread.getState());thread.start();for (int i = 0; i < 3; i++) {System.out.println(thread.getState());Thread.sleep(200);}thread.join();System.out.println(thread.getState());}
}

 

 

相关文章:

Java线程 - 详解(1)

一&#xff0c;创建线程 方法一&#xff1a;继承Thread类 class MyThread extends Thread{Overridepublic void run() {System.out.println("线程1");} }public class Test {public static void main(String[] args) {MyThread myThread new MyThread();myThread.…...

结构体-C语言(初阶)

目录 一、结构体声明 1.1 结构概念 1.2 结构声明 1.3 结构成员的类型 1.4 结构体变量的定义和初始化 二、结构体成员的访问 2.1 结构体变量访问成员 2.2 结构体指针访问指向变量的成员 三、结构体传参 一、结构体声明 1.1 结构概念 结构是一些值的集合&#xff0c;这些值称为…...

【网络】HTTPS的加密

目录 第一组&#xff0c;非对称加密第二组&#xff0c;非对称加密第三组&#xff0c;对称加密证书签名 HTTPS使用的是非对称加密加对称加密的方案 &#xff08;非对称加密&#xff1a;公钥加/解密&#xff0c;私钥解/加密&#xff09; &#xff08;对称加密&#xff1a;一组对称…...

Nacos安装指南

Nacos安装指南 1.Windows安装 开发阶段采用单机安装即可。 1.1.下载安装包 在Nacos的GitHub页面&#xff0c;提供有下载链接&#xff0c;可以下载编译好的Nacos服务端或者源代码&#xff1a; GitHub主页&#xff1a;https://github.com/alibaba/nacos GitHub的Release下载…...

java-Optional 类详解

目录 前言 Optional的构造方法 Optional的相关方法介绍 isPresent用法&#xff1a; get用法&#xff1a; filter用法&#xff1a; orElse用法&#xff1a; orElseGet用法 orElseThrow用法 map用法 flatMap用法&#xff1a; 前言 Optional 类是java8的新特性&#xff0…...

sql数据库怎么备份,sql 实时备份

在当今互联网时代&#xff0c;数据已经成为企业的核心资产。然而&#xff0c;数据的安全性和完整性面临硬件问题、软件故障、人工操作错误等各种威胁。为了保证数据的安全&#xff0c;实时备份已经成为公司必须采取的重要措施之一。下面我们就重点介绍SQL实时备份的重要实施方法…...

RK3399平台开发系列讲解(存储篇)Linux 存储系统的 I/O 栈

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 文章目录 一、Linux 存储系统全景二、Linux 存储系统的缓存沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 Linux 存储系统的 I/O 原理。 一、Linux 存储系统全景 我们可以把 Linux 存储系…...

Java“牵手”天猫淘口令转换API接口数据,天猫API接口申请指南

天猫平台商品淘口令接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取天猫商品的标题、价格、库存、商品快递费用&#xff0c;宝贝ID&#xff0c;发货地&#xff0c;区域ID&#xff0c;快递费用&#xff0c;月销量、总销量、库存、详情描…...

postgresql 条件表达式

postgresql 条件表达式 简单CASE表达式搜索CASE表达式缩写函数nullif函数示例 coalesce函数 总结 简单CASE表达式 语法如下 case 表达式when 值1 then 结果1when 值2 then 结果2else 默认值 end;select e.first_name , e.last_name , case e.department_id when 90 then 管…...

姜启源数学模型第五版第五章火箭发射升空

姜启源数学模型第五版第五章例题内容复现 数学建模背景1.学习内容火箭发射升空理论知识 2.例题3.问题分析不考虑空气阻力的模型考虑空气阻力的模型 4.代码内容复现不考虑空气阻力考虑空气阻力模型 数学建模背景 首先先简单的介绍数学建模是一个怎么样的内容 数学建模是一种将数…...

局域网中电脑共享文件给手机

学习资源&#xff1a; 局域网共享&#xff1a;这样设置&#xff0c;你可以轻松拷贝任何电脑的文件。_哔哩哔哩_bilibili 可以实现什么效果&#xff1f; 连接同一个WIFI&#xff0c;电脑端为服务端&#xff0c;提供共享文件&#xff0c;手机是客户端&#xff0c;可以读取服务端…...

线段树练习

P1198 [JSOI2008] 最大数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) // Problem: P1198 [JSOI2008] 最大数 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P1198 // Memory Limit: 128 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://c…...

Mybatis映射.动态sql.分页

介绍&#xff1a; 动态SQL是MyBatis提供的一种动态生成SQL语句的方式&#xff0c;可以根据不同的条件生成不同的SQL语句&#xff0c;从而实现更加灵活的查询和操作。 在MyBatis的映射文件中&#xff0c;可以通过使用if、choose、when、otherwise、foreach等标签来实现动态SQL…...

springboot向resources下写文件的两种方式

文章目录 方式一&#xff1a;方式二&#xff1a; 方式一&#xff1a; import java.io.File; import java.io.FileWriter; import java.io.IOException;public class WriterFileUtils {private static final String prefix "classpath:";public static void writeFi…...

Sloare flare网卡信息

详细的安装信息 https://github.com/Xilinx-CNS/onload/tree/master/scripts 进行下载 Solarflare网卡开发&#xff1a;openonload 安装与调试_openonload安装_Erice_s的博客-CSDN博客 cns-sfnettest测试 cns-sfnettest 下载 https://github.com/Xilinx-CNS/cns-sfnettes…...

Redis知识点整理

第一部分&#xff1a;Redis基础知识点 1、数据类型 5种常用基础类型&#xff1a;string,hash,list,set,zset – 字符串&#xff0c;Hash表&#xff0c;List顺序集合&#xff0c;Set无序集合&#xff0c;ZSet有序集合3中特殊类型&#xff1a;bitmap-字节地图, hyperloglog-统计…...

React笔记(一)初识React

一、React概述 1、什么是react react的官网:React 用于构建用户界面的 JavaScript 库&#xff0c;它也是一个渐进式的用于构建用户界面的javascript框架 2、主要特征 声明式&#xff1a;使用原生JS编写的页面存在着开发效率低下、性能较差的情况&#xff0c;使用react大家就…...

C语言——指针进阶(一)

目录 ​编辑 一.字符指针 1.1 基本概念 1.2 面试题 二.指针数组 三.数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 四.数组参数、指针参数 4.1 一维数组传参 ​编辑 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 ​编辑 五.…...

【ArcGIS Pro二次开发】(62):复制字段

应网友需求&#xff0c;做了这么一个复制字段的小工具。 假定这样一个场景&#xff0c;手头有一个要素1&#xff0c;要素里有10个字段&#xff0c;另一个要素2&#xff0c;除了shape_area等图形字段外&#xff0c;没有其它字段。 现在的需求是&#xff0c;想把要素1中的8个字…...

【Tkinter系列02/5】界面初步和布局

本文是系列文章第二部分。前文见&#xff1a;【Tkinter系列01/5】界面初步和布局_无水先生的博客-CSDN博客 说明 一般来说&#xff0c;界面开发中&#xff0c;如果不是大型的软件&#xff0c;就不必用QT之类的实现&#xff0c;用Tkinter已经足够&#xff0c;然而即便是Tkinter规…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)

引言 工欲善其事&#xff0c;必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后&#xff0c;我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集&#xff0c;就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving

地址&#xff1a;LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂&#xff0c;正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...