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

多线程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毫秒。

相关文章:

  • C++语法系列之类型转换
  • 『React』组件副作用,useEffect讲解
  • 12:点云处理—调平,角度,平面度,高度,体积
  • Oracle双平面适用场景讨论会议
  • 【MATLAB代码】制导——三点法,二维平面下的例程|运动目标制导,附完整源代码
  • 【Typst】6.布局函数
  • .Net Framework 4/C# 初识 C#
  • 由docker引入架构简单展开说说技术栈学习之路
  • 基于 NXP + FPGA+Debian 高可靠性工业控制器解决方案
  • Dify知识库下载小程序
  • Jpom:Java开发者的一站式自动化运维平台详解
  • RabbitMQ在SpringBoot中的应用
  • RNN结构扩展与改进:从简单循环网络到时间间隔网络的技术演进
  • 网络安全运维实训室建设方案
  • Matlab数值计算
  • YOLO学习笔记 | 一种用于海面目标检测的多尺度YOLO算法
  • 用HTML5 Canvas打造交互式心形粒子动画:从基础到优化实战
  • 悟饭游戏厅iOS版疑似流出:未测试版
  • Pycharm的使用技巧总结
  • Python实例题:Flask实现简单聊天室
  • 岳阳网站建设/宁波网站推广哪家公司好
  • 中企动力网站合同/1000个关键词
  • 网站建设马鞍山/整合营销策略有哪些
  • 昆山便宜做网站/seo关键词排名优化软件怎么选
  • 网站首页图片切换代码/seo优化网站的注意事项
  • 做网站前台用什么问题/百度指数人群画像怎么看