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

多线程1(Thread)

认识线程(Thread)

在进程中,要创建一个进程和销毁一个进程所消耗的硬件和软件资源是巨大的,因此为了优化上述过程,我们引入了“线程”。

线程是系统调度的基本单位。

1)线程和进程的关系

可以认为进程包含线程,一个进程里最少有一个线程,每个线程都可以单独执行一段逻辑,并且可以单独在CPU上调度,因此线程可以叫做“轻量级进程”。

在一个进程中,多个线程共享进程资源,而在后面在这一进程中创建的线程就直接使用进程创建的资源,可以省下申请资源的开销。

2)线程安全问题

当两个线程同时对同一个变量进行修改时,可能会引发线程之间的冲突,这时就会引发线程安全问题(后面详解)。

使用代码实现线程

线程是操作系统中的概念,操作系统中实现了线程这样的机制,因此操作系统对用户层提供了一些API供用户调用,JAVA中就是用Thread这个类进行封装。

Thread类:Thread是JAVA中标准库里的一个类,操作系统本身提供了一些函数进行操作线程,JVM就把这些函数封装成JAVA版本的Thread,这里操作Tread就是操作线程。

五种创建线程的方法:

1)定义一个静态内部类继承自Thread,实现Thread中的Run方法,创建一个这个静态内部类的实例。

public class dome2 {static class MyThread extends Thread{@Overridepublic void run() {System.out.println("hah");}}public static void main(String[] args) {Thread dome = new MyThread();dome.start();}
}

Run方法就是进行执行一段逻辑的入口,run不需要代码显性调用。

注意点1:Start方法就是真正在操作系统中创建一个线程,run方法就是这个线程要执行逻辑的入口,这里如果只是调用run方法就会只执行main这个主线程而不会创建一个新的线程,以一段代码为例:

上述代码调用了start方法,创建了一个新的线程,所以创建的线程和主线程会并发执行,两个打印操作会同时进行。

如果将start去掉,直接调用run,就会只执行主线程,将run中的逻辑执行完才会执行下面,但是run中是死循环,因此只会打印出hah。

注意点2:主线程和新线程之间的执行顺序是由操作系统随机执行的,我们可以通过第三方工具JDK中的jconsole进行观察线程的执行情况。

2)创建一个子类,实现Runnable接口,重写Run方法,搭配Thread进行start

3)创建一个匿名内部类,重写run方法,start方法

4)创建一个runnable的匿名内部类,重写run方法,调用start

5)最简单的写法,在Thread中使用lambda表达式

线程中的几个常见属性

JAVA中对线程的状态进行了进一步扩充(后面细说)

1)后台线程:线程没执行完,进程可以结束(线程不可以结束进程)。

前台线程:线程没执行完,进程不可以结束(线程可以组织进程结束)。

main线程和我们自己创建的线程是前台线程,其他的都是后台线程。

我们可以通过setDaemon设置前台线程为后台线程(必须在线程start前设置),后台线程结束程序就结束了。

(这个程序当主线程运行三次之后结束进程,我们创建的后台线程就会随进程结束而结束)

2)是否存活

当线程没结束时就是true,结束或还没开始执行就是false

启动一个线程

启动一个线程要调用start,调用start才是真正调用系统中创建线程的api,而线程启动后会自动调用run中的内容。

1.调用start是非常快的,不会有任何的阻塞等待。

这里调用完start后就立刻调用下面得sout,打印出main和thread,但是要注意这里先打印出的是main,这是因为调用start后要创建线程。并不是一直是这样的,可能会有例外,这是因为系统调用线程是随机调度的。

2.一个线程只能start一次

一个线程start后就是就绪/阻塞状态,而对于阻塞/就绪状态的线程,就不能start了。

对于一个Thread而言,对应着操作系统中的一个线程。

中断(打断)一个线程

1.通过变量

通过修改线程内的变量进行打断

2.使用isInterrupted和interrupt中断

这里的currentThread是获取到调用此方法对象的引用,isInterrupted是默认false,下面的interrupt是将条件改为true。

注意事项:

如果在线程里加上sleep,再在main中调用interrupt,就会提前唤醒线程,触发异常,同时将isInterrupted重置为false。

总结:1).没使用sleep等阻塞操作时,interrupt会将isInterrupted从false改为true。

2).使用sleep的阻塞操作时,调用interrupt会抛出interruptException异常,将isInterrupted重置为false,同时提前唤醒sleep,但此时我们可以在catch中进行进一步操作,手动决定线程是否结束。

线程的等待

操作系统调用线程是随机调度(抢占式执行),线程等待就是约定好线程的结束顺序。

1.使用join进行等待

这里就是main等待线程t结束,再执行mian中的逻辑,这里的join是死等。

main等待线程t也是可以的,但是要获取的main的引用。

join不一定执行阻塞,当执行join时线程结束,join就不会阻塞等待。

join还有一个重载版本,设置等待的最大时间,最多等待xxx毫秒。

http://www.lryc.cn/news/2398014.html

相关文章:

  • NVIDIA DOCA 3.0:引领AI基础设施革命的引擎简析
  • 小家电外贸出口新利器:WD8001低成本风扇智能控制方案全解析
  • 【软件测试】web自动化:Pycharm+Selenium+Firefox(一)
  • C++实现汉诺塔游戏用户交互
  • 谷歌地图手机版(Google maps)v11.152.0100安卓版 - 前端工具导航
  • AJAX对于XML和JSON的处理
  • C++核心编程_关系运算符重载
  • NIO知识点
  • T/CCSA 663-2025《医疗科研云平台技术要求》标准解读与深度分析
  • win11回收站中出现:查看回收站中是否有以下项: WPS云盘回收站
  • Nginx+Tomcat 负载均衡群集
  • SCDN如何同时保障网站加速与DDoS防御?
  • Trae CN IDE 中 Python 开发的具体流程和配置总结
  • PostgreSQL不同的等级认证体系
  • 项目前置知识——不定参以及设计模式
  • 04powerbi-度量值-筛选引擎CALCULATE()
  • JavaScript排序算法详解:从基础到高级
  • chromedriver 下载失败
  • Weather app using Django - Python
  • 机器视觉2,硬件选型
  • 自定义序列生成器之单体架构实现
  • 电阻电容的选型
  • 12.springCloud AlibabaSentinel实现熔断与限流
  • Cookie 和 Session:Web 身份验证的核心机制
  • vSOME/IP与ETAS DSOME/IP通信的问题解决方案
  • 修改vscode切换上一个/下一个标签页快捷键
  • 三大中文wordpress原创主题汉主题
  • 软考-系统架构设计师-第十五章 信息系统架构设计理论与实践
  • Redis缓存-数据淘汰策略
  • 52. N 皇后 II【 力扣(LeetCode) 】