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

javaEE之线程初步认识

一、为什么要用多线程

        因为多线程他能让程序同时进行工作,如:一个程序中,一个线程用来接受请求,另一个线程用于计算。如果是单线程的话,就只能一个结束后再进行下一个。

        但此时肯定会右朋友问,用进程也可以实现这功能啊,为什么要用线程。你说得对,但是,相对于多线程而言,其实进程的创建销毁的开销是很大。这里就要讲一下线程和进程的关系了

        众所周知,电脑内部有一个叫CPU的元件,它能能接受线程和进程的执行指令,就好比CPU是工人,而线程进程是任务,任务分配给工人去做。其中,任务中肯定也有大任务包含小任务,如:计划出国旅游(大任务指出国旅游,小任务指做攻略,订酒店等细节)。而这时,我们就能理解成进程是大任务,线程是小任务

        同时,每个出国旅游的计划(进程),都有独立的预算和行李(体现出进程和进程之间资源是不共享的)。其中一个出国旅游计划泡汤了,不会影响到其他的旅游计划(体现了进程与进程的独立性),并且启动一个旅游计划成本较高(体现了创建进程的开销大)。而小任务中的每一样都有牵连,如预算的多少影响酒店的选择等(体现了线程与线程间共享线程资源)。计划中的细节可以随意添加(体现线程创建开销小),小任务间可以方便交流(体现线程通信成本低),并且酒店等细节会影响大任务(体现线程会引起进程崩溃

        因此,综上描述,我们能总结到以下几点

                        1.线程的开销比进程的开销要小

                        2.进程包含线程,一个进程有多个线程

                        3.每个线程都是一个执行流,都可以放在CPU上调度执行,线程是操作系统调度执行的基本单位

                        4.进程间资源是不能共享,线程间资源是共享的

                        5.某个线程的出错,会影响整个进程

二、创建多线程

1.创建子类,继承Thread,重写run

2.使用Runnable接口

3.继承Thread,使用匿名内部类

4.实现Runnable,使用匿名内部类

                                                       或者是

5.用lambda表达式,一般使用这种

6.问题

        看到这里,有些小伙伴可能会疑惑,为什么Thread和Runnable。使用时,为什么不用import包啊?其实,Thread和Runnable这两个类是在java.lang包中,java.lang包这个是特殊的包,能够被默认import

        那为什么用同一个Thread对象,重复start会报错的?那是因为,Java中约定了一个Thread对象,和一个操作系统线程是“一一对应的”,也就是说一个Thread对象只能start一次        

三、查看线程运行情况

        查看线程运行情况,我们可以打开我们 jdk 的文件夹,点进 bin 文件夹,找到 jconsole.exe 

        点进去后,点本地进程,再选择刚刚运行线程的类名,点击连接    

        进去后,点击线程按钮,就进到线程的页面了

        这就是之这个类所有线程了

四、属性及其方法

1.常见的属性

        前台线程会阻止整一个线程结束,后台线程不会阻止整个线程结束。就好像在饭桌上,领导是前台线程,员工是后台线程。当领导吃饱了,他能够直接让饭局结束,但如果员工吃饱了,并不行,他需要等待领导的指示来做事。当然,能用代码体现,如代码:  

        而主线程包括代码中创建的线程,默认都是前台线程,如代码:

2.常见的方法

1.修改线程名字        

        其中,我们想给线程起个名字时,我们能这样做,再lambada里面加引号,引号里写线程的名称

2.使用interrupt中断线程

        中断一个线程。对于Java来讲,一个线程终止,就是这个线程入口方法执行完毕。也就是说java不提供强制终止(所有让线程终止的方法,都要围绕入口方法执行)。就如当A线程对B线程执行终止,不能强制终止,这样是不安全的,因为不确定B线程正在做什么。强制终止会导致程序崩坏。

        如下面代码就是能进行终止,当输入0的时候,线程t就终止

        不过值得注意的是,running这个变量需要是final或者是事实final(指没有final修饰,但这个变量并没有被修改)。因为在Java中,lambada变量捕获时要求时final或者时事实final。为什么呢?其实,Java中捕获变量是将变量的值拷贝一份。一旦拷贝不一致,代码就会乱。那为什么写成成员变量就可以呢?因为当写成成员变量时,触发的就不是lambada捕获变量,而是内部类访问外部类。众所周知,lambada其实本质上是基于函数式接口的匿名内部类。所以就没有限制,但访问局部变量就是有限制的,下面是错误示范:

        OK,细节弄明白后,这时有会有一个问题出现,当sleep里面的时间变成100s的时候,我们就发现,当我们输入完零之后,他并非立即停止,而是一直保持sleep状态,直到100s过后,不符合我们的预期。所以,这时我们要将while里面的条件进行修改,用isInterupted来进行判断,与线程方法interrupt配合使用。并且此处的cur和t其实是同一个线程对象

        可是,值得注意的是,虽然两个是同一个对象,但不能省略创建当前线程对象这一步。原因就是Java在执行的时候都是先对构造方法的参数从左到右依次求值,然后再创建对象,最后赋值给左边变量,所以一定先是对Thread()括号中参数进行求值。再执行Thread这个构造方法,再把Thread的构造方法的结果,赋值给t,定义t。通俗的讲就是从后往前编译,先编译蓝色圈内的代码,再编译黄色圈的代码

        因此,在第一阶段的时候这个t还没有被创建出来,不能这样写。那如果是这样呢

        语法上是可以的,但是要保证t这个对象是不可变的,接着,再将if内的代码进行修改,直接使用Thread中的interrupt方法来进行终止。由于interrupt这个方法不仅能设置标志位,还能唤醒sleep等导致阻塞的方法,会使sleep抛出异常。所以是整个程序按预期进行

        不过,这个强制唤醒的方法,它会将标志位进行了重置,如果使用的是打印异常的处理的话,会导致多输出一次hello Thread,而throw不会,这是因为throw搞完之后,他会中断线程,而打印异常不会,但如果我们在打印异常的后面加个break,那就能阻止这个情况发生

3.jion方法的使用

        这个是用来让一个线程先执行,让另一个线程后执行的方法。因为当线程被start时,他要进行三步,调用api、系统创建线程以及系统线程调度。以下面这个代码为例:

        导致这样的结果的原因可能是系统创建线程需要一定时间,在还没创建完,主线程就已经到输出这一步了,导致result并没有进行计算就被打印了。所以当我们使用join时,就能解决这个问题

        这里join是表示main线程等待 t线程 执行完后,再执行。这里的join的时间是不确定的,取决于 t 何时退出。所以,为了避免长期阻塞,我们能在括号内添加时间。当超过这个指定时间,join只是从阻塞状态变成就绪状态,至于下一步如何做,还要等待系统调度

4.获取线程名字

        我们能在线程里使用getName方法来获取线程名字,但如果在Runnable这个对象里,就不能了,因为它不支持这个方法,我们只能通过创建当前线程对象来进行使用此方法

五、六种状态

        Java中给线程引入六种状态

1.new

        创建了对象,但没start

public class Demo7 {public static void main(String[] args) {Thread t = new Thread(() -> {});System.out.println(t.getState());t.start();}
}

2.terminated

        操作系统内部线程已经销毁了,但Thread对象还在。也就是线程入口方法执行完毕

public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {});t.start();Thread.sleep(10);System.out.println(t.getState());}
}

3.runnable

        可工作的。又可以分成正在工作的和即将开始工作的

public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {Thread cur = Thread.currentThread();System.out.println("hehe");System.out.println(cur.getState());});t.start();}
}

4.waiting

        死等状态

public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread manThread = Thread.currentThread();Thread t = new Thread(() -> {while(true){System.out.println("主线程: " + manThread.getState());try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();t.join();}
}

5.timed_waiting

        带有超时间等待

public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread manThread = Thread.currentThread();Thread t = new Thread(() -> {while(true){System.out.println("主线程: " + manThread.getState());try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();t.join(100000);}
}

6.blocked

        特指由于锁引起的阻塞

public class Demo7 {public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread manThread = Thread.currentThread();Thread t = new Thread(() -> {Thread cur = Thread.currentThread();synchronized (locker) {try {Thread.sleep(1000_000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});Thread t1 = new Thread(() -> {Thread cur1 = Thread.currentThread();synchronized (locker){}});t.start();Thread.sleep(100);t1.start();Thread.sleep(500);System.out.println(t1.getState());}
}

        好啦,这期内容就先到这啦,欢迎大家留言指正!!!


文章转载自:

http://HLwrOr4n.rbffj.cn
http://n56NV2P9.rbffj.cn
http://BJ4mQUek.rbffj.cn
http://4nd8N2qO.rbffj.cn
http://CzyknmyT.rbffj.cn
http://q8MaqDpJ.rbffj.cn
http://MKfCA8XS.rbffj.cn
http://oTRukIL9.rbffj.cn
http://eWWqLERs.rbffj.cn
http://RbzYOGaE.rbffj.cn
http://jmXHtrCj.rbffj.cn
http://9uqeeLqX.rbffj.cn
http://gG63ahmj.rbffj.cn
http://DgVGs2AX.rbffj.cn
http://s7Kask5b.rbffj.cn
http://uWmplvdn.rbffj.cn
http://1S68jHmc.rbffj.cn
http://h8rnvrd6.rbffj.cn
http://gDXgGcnm.rbffj.cn
http://BD3Yd6QK.rbffj.cn
http://yBEtWCxF.rbffj.cn
http://q8Hjjrck.rbffj.cn
http://U73uxG89.rbffj.cn
http://z1XyWPhH.rbffj.cn
http://PlQp2Zzj.rbffj.cn
http://qqRGNB4E.rbffj.cn
http://rTJbX1IZ.rbffj.cn
http://7xcnZAgN.rbffj.cn
http://cuDU4Euy.rbffj.cn
http://SqVWWCJr.rbffj.cn
http://www.dtcms.com/a/377845.html

相关文章:

  • `struct iovec`详解
  • python超市购物 2025年6月电子学会python编程等级考试一级真题答案解析
  • 项目模块划分
  • leetcode18(无重复字符的最长子串)
  • HackathonCTF: 1
  • redis cluster(去中心化)
  • 量子机器学习入门:三种数据编码方法对比与应用
  • 【Mysql】数据库的内置函数
  • 【Unity基础】枚举AudioType各个枚举项对应的音频文件类型
  • 2025数字化转型时代必备证书有哪些?
  • 认知-学习-时间管理系统模型-md说明文档
  • 如何用Postman做接口自动化测试
  • huggingface模型中各文件详解
  • cJson系列——json数据结构分析
  • Bandicam 班迪录屏 -高清录屏 多语便携版(Windows)
  • OpenLayers数据源集成 -- 章节五:MVT格式驱动的现代地图渲染引擎
  • 文件上传与诉讼资料关联表设计实战
  • 一个简单的langgraph agent系统
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(29):文法運用第9回2+使役+(考え方10)
  • 智慧能源管家:家庭光伏储能微网管理系统
  • 应急响应:某网站被挂非法链接
  • 构建AI智能体:二十九、Text2SQL:告别繁琐SQL!用大模型自助生成数据报表
  • 【Office 2024 LTSC 安装和使用指南】
  • Counting Towers (动态规划)
  • Linux内核崩溃时为什么会打印call trace---猝死前的死亡讯息
  • SQL嵌套查询详解:理论+实战提升查询性能
  • 硬件 (七) ARM 软中断, IMX6ULL 点灯
  • 图解网络基础篇
  • .Net程序员就业现状以及学习路线图(五)
  • Golang Panic Throw Map/Channel 并发笔记