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

Java EE - Thread类的基本使用

目录

  • 1.Thread类的基本介绍
  • 2.创建线程
    • 2.1 自定义线程类MyThread
    • 2.2 自定义一个MyRunable类
    • 2.3 Thread 和 Runnable
    • 2.4 lambda表达式
  • 3. sleep方法
  • 4.currentThread方法
  • 5.线程的终止
  • 6.小结

1.Thread类的基本介绍

Thread类是Java标准库中提供用来管理线程的类,里面封装操作系统对线程管理方面的API,Java中创建的每一个线程,可以理解为Thread类的实例化对象,用来描述线程信息,可以视为Thread类是对操作系统提供线程管理的API进一步的抽象和分离。

2.创建线程

2.1 自定义线程类MyThread

定义一个MyThread类,继承于Thread类,Thread中有一个run方法,需要在子类中重写,MyThread类重写完成后,实例化MyThread的对象,就完成线程的创建,但是线程的真正的调用需要使用Thread类或者子类中的start方法,才会启动线程,在创建线程后就可以调用start方法

//自定义一个MyThread类继承于Thread类,出现Thread类中的方法
class MyThread extends Thread{@Overridepublic void run(){System.out.println("run方法已经启动。");}
}
public class Main{public static void main(String[] args){//实例化一个线程类MyThread myThread = new MyThread();//启动线程myThread.start();}
}

在这里插入图片描述

2.2 自定义一个MyRunable类

MyRunnable类使用Runnable接口,重写接口中的run方法,但是线程的创建需要使用到Thread类,因此还需要创建一个Thread类,将MyRunnable实例化对象作为Thread类构造方法的参数。

在Thread类中提供一个参数为Runnnable接口引用的构造方法,可以将引用传入。

//Thread类的构造方法public Thread(Runnable target) {this(null, target, "Thread-" + nextThreadNum(), 0);}
class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("MyRunnable: run方法已经启动。");}public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread t = new Thread(myRunnable);}
}

在这里插入图片描述

2.3 Thread 和 Runnable

Thread类是Java标准库提供用来管理线程的类,但是内部并没有具体实现run方法,而是调用Runnable接口中的run方法,Runnable是一个接口,内部也没有实现run方法,所以需要创建Thread的子类或者将使用Rnnbale接口的类的对象作为Thread构造方法的参数。

//Thread类的run方法@Overridepublic void run() {if (target != null) {target.run();//进入run方法,实际使用Runnable的run方法}}
@FunctionalInterface
//Runnable的run方法
public interface Runnable {public abstract void run();
}

Thread的子类可以使用匿名内部类的方式创建,在子类中重写run方法。

//匿名内部类创建
class out{public static void main(String[] args) {//使用Thread作为匿名内部类的父类Thread thread = new Thread(){//重写run方法,实际调用的是重写的run@Overridepublic void run(){System.out.println("out: run方法启动");}};//启动线程thread.start();}
}

在这里插入图片描述
Runnable的子类使用匿名内部类的方式创建,使用Runnable接收实例化对象,再将对象引用传入Thread的构造方法中。

class Rout{public static void main(String[] args) {Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("Runnable: run方法启动");}};Thread thread = new Thread(runnable);//启动线程thread.start();}
}

在这里插入图片描述

2.4 lambda表达式

lambda表达式创建的匿名内部类的对象引用作为Thread类构造方法的参数传入。


class Lambda{public static void main(String[] args) {Thread thread = new Thread(//lambda表达式创建的() -> {System.out.println("Lambda: run方法已启动");});//启动线程thread.start();}
}

在这里插入图片描述

3. sleep方法

sleep方法是让线程的执行进入等待,可以传入一个参数,单位是毫秒,例如sleep(1000)就是休眠等待一秒,sleep方法会让线程进入等待,这个方法默认是在线程中是不安全的,需要取捕获异常**InterruptedException**(每个让线程进入等待的方法都会捕获的异常),捕获异常的方法有两种,第一种是在sleep方法中加上try catch,第二种是在main方法中加上声明,最终由JVM处理异常。

例如 :重写的run方法中输出10次打印,每次间隔1000毫秒,记录调用sleep程序的执行的时间。

class Sleep{public static void main(String[] args) {Thread thread1 = new Thread(() ->{long start = System.currentTimeMillis();//开始for (int i = 0; i < 10; i++) {System.out.println("run方法打印中------");//捕获异常try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}};long end = System.currentTimeMillis();//接收System.out.println("时间:" + (end - start) + "ms");//毫秒});//启动线程thread1.start();}
}

在这里插入图片描述

4.currentThread方法

currentThread方法是Thread类中实现的静态方法,可以通过Thread类调用,currentThread方法可以获取当前线程执行的对象引用,使用该引用就可以执行Thread中的方法,如sleep,getName(获取线程名字)。

class Test{public static void main(String[] args) {Thread thread = new Thread(() -> {//记录sleep函数的执行时间long s = System.currentTimeMillis();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}long e = System.currentTimeMillis();System.out.println("sleep休眠时间:" + (e - s));//获取线程名System.out.println("获取当前线程名字:" + Thread.currentThread().getName());});thread.start();}
}

在这里插入图片描述
线程如果未命名,系统默认线程名是Thread-0,如果需要重命名可以在Thread的构造方法中多传入一个参数name,作为线程名字.

//Thread类中的构造方法,一个是Runnable对象引用,一个是线程名public Thread(Runnable target, String name) {this(null, target, name, 0);}
class Test{public static void main(String[] args) {Thread thread = new Thread(() -> {long s = System.currentTimeMillis();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}long e = System.currentTimeMillis();System.out.println("sleep休眠时间:" + (e - s));System.out.println("获取当前线程名字:" + Thread.currentThread().getName());},"线程1");//添加线程名字thread.start();}
}

在这里插入图片描述

5.线程的终止

线程的终止有两种方法:

1.第一种是使用标识符,定义一个变量flag,通过改变flag使线程提前终止

例如:定义一个布尔类型的变量flag,初始默认为false,当flag更改为true时,停止线程。

class T{//定义标识符static boolean flag = false;public static void main(String[] args) {Thread thread = new Thread(() -> {//标识符控制while(!flag){System.out.println("线程最执行中----");System.out.println("输入1停止线程,输入其它继续线程");System.out.print("请输入:");Scanner in = new Scanner(System.in);if(in.nextInt() == 1) flag = true;//改变标识符终止线程}System.out.println("线程结束");});thread.start();}
}

在这里插入图片描述

如果此时将标识符设置在mian函数内,是否可以正确执行呢?

在这里插入图片描述
可以看到将标识符在main方法定义,程序就会报错,错误是因为lambda表达式内部变量的使用会触发“变量捕获” 的机制,被捕获的局部变量需要满足是被final修饰的,或者实际上是final的(不被修改的),当flag是可被修改的就会在编译时报错。

多个线程的执行是并发执行的,例如在上述出现中就有main线程(主线程)和Thread-0线程,在Thread线程开启的同时,main线程也会开启,并发执行,在lambda中使用的变量是一份临时的拷贝,并不是原有的变量,main线程结束时,捕获的变量也可以继续使用,不会因线程的结束而无法使用,但是如果捕获的变量是可修改的,main线程可能修改后,还未等到lambda表达式去拷贝修改后的变量就结束线程,导致捕获的结果错误,所以lambda表达式中的局部变量必须是final或者实际上是final的。

在这里插入图片描述

为什么在类中定义的静态变量不会报错?

类中的静态变量在类加载的时候存放于静态区,访问可以通过类或者成员方法访问,类成员变量的销毁伴随类的销毁,而线程的结束通常是比类的销毁更快(类的销毁涉及GC垃圾回收的复杂机制),所以在类中定义的成员变量在lambda表达式中不会出现报错信息。

2.线程终止的第二种方法是调用interrupt方法,提前终止线程,interrupt方法通常搭配isInterruoted方法使用,isInterrupted方法可以认位是调用标识符,interrupt方法是将标识符改变,终止线程。

//isInterrupted方法默认调用标识符,interrupted = falseprivate volatile boolean interrupted;
class Interrupt{public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {//判断是否终止线程while(!Thread.currentThread().isInterrupted()){System.out.println("线程执行中.....");try {Thread.sleep(1000);} catch (InterruptedException e) {//未输出异常原因}}});//开启线程thread.start();//确保调用interrupt方法线程开始执行Thread.sleep(1);//终止线程thread.interrupt();}
}

在这里插入图片描述
程序执行后会一直打印线程执行中,并没有终止线程,这是因为在调用interrupt方法的时候会先把isInterrupted方法获取的标识符改为true,但是interrupt方法会重新唤醒sleep方法,又将标识符改为false,导致线程继续执行。

可以在捕获异常后执行输出异常的原因,终止线程。

     try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);//抛出异常,终止进程}

在这里插入图片描述
在catch中直接加入break,可以终止线程,不会立马终止进程。

   try {Thread.sleep(1000);} catch (InterruptedException e) {System.out.println("线程结束");break;}

在这里插入图片描述

6.小结

本篇内容涵盖了Java EE中Thread类的基本使用,包括线程创建、休眠、获取当前线程以及线程终止等核心操作。掌握这些基础知识为理解多线程编程的状态管理、线程安全及设计模式应用奠定基础。后续内容将深入探讨线程的状态转换及相关技术细节,进一步扩展Java EE多线程编程的实践能力。

期待下次继续带你深入Java EE的更多技术细节,下期见!

http://www.dtcms.com/a/568488.html

相关文章:

  • 社会真相社会现实丛林社会强者思维社会关系价值交换社会法则社会圈子社会阶层电子书籍PDF
  • 轻量化的网络模型:SqueezeNet 详解与复现(已解决)
  • Adobe Acrobat DC PDF如何批量文本替换
  • 帝国cms 微信小程序获取手机号码的api接口
  • 南昌网站搭建服务免费涨1000粉丝网站
  • linux USB摄像头不停掉线问题
  • 本地开发调试企业微信回调接口不顺畅?利用 CPolar 实现内网穿透,快速建立公网访问通道
  • 金融数仓项目介绍
  • 《投资-154》Beta(贝塔系数)是金融领域中用于衡量资产(如股票、基金、投资组合)系统性风险的核心指标,它反映了资产相对于市场整体波动的敏感程度。
  • 【开发技能】借助Aspose.Words,用C#开发一个Markdown到 Word的转换器
  • React 中 useCallback 的基本使用和原理解析
  • 做网站架构深圳精美网站设计
  • OpenCV(十九):图像的加法运算
  • 基于单相机的双目视觉三维重构项目:使用深度学习方法计算视差图
  • Unity UGC IDE实现深度解析(五):事件系统与消息传递
  • 苏州市建设工程交易中心网站网站开发设计总结及心得体会
  • 黑龙江省鹤岗市城乡建设局网站建站域名
  • soular零基础学习,如何实现TikLab工具链统一登录认证
  • Go语言设计模式:解释器模式详解
  • 深圳的游戏公司后端开发面经
  • 全新私域(微信)管理系统如何获取?
  • 《Godot轻量化开发的全流程进阶指南》
  • 首个开源方案:将 Godot 3D 游戏无缝嵌入 React Native 应用
  • Qt在线安装测试可用的国内代理
  • React Native第五章
  • 如何提高测试用例覆盖率?
  • 蒙古网站群建设html做的网站排版导致乱码
  • 【国产桌面操作系统】QT应用打deb包
  • React 12
  • 做网站 怎么发布专业模板建站哪家好