欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > JavaEE——Thread类的基本用法

JavaEE——Thread类的基本用法

2025/4/21 4:19:07 来源:https://blog.csdn.net/2301_80817503/article/details/147026021  浏览:    关键词:JavaEE——Thread类的基本用法

目录

  • 前言
  • 1.线程创建
    • 1.1 继承Thread类
    • 1.2 实现Runnable接口
    • 1.3 使用lambda表达式
  • 2.线程中断
    • 2.1 使用变量中断线程
    • 2.2 使用内置的标志位
  • 3.线程等待
  • 4.线程休眠和获取线程引用
  • 总结

前言

上篇文章简单介绍了进程和线程,这边文章来简述一下Java中Thread类的基本用法,在Java中使用多线程编程。

1.线程创建

1.1 继承Thread类

我们创建一个继承自Thread的内部类,同时重写Thread的run()方法这里重写run()方法是用于编写我们想要此线程所要执行的功能的代码。即线程的入口

//继承 Thread, 重写 run
class MyThread extends Thread{@Overridepublic void run() {System.out.println("线程运行");}
}

而后创建示例并且启动线程

public class Demo1 {public static void main(String[] args) {//创建线程对象MyThread t = new MyThread();//启动线程t.start();}
}

注意,这里不能使用t.run()这是由于t.run()是用于执行线程,并不能创建一个新线程,虽然结果一样,但是是在主线程执行的,这里的t.start()是首先创建一个新线程,而后调用我们的run()方法,从而实现多线程编程。

此外,此代码可以使用匿名内部类来进行简化:

//继承 Thread, 重写 run, 使用匿名内部类
public class Demo3 {public static void main(String[] args) {Thread t = new Thread(){@Overridepublic void run() {System.out.println("线程运行");}};}
}

1.2 实现Runnable接口

class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("线程运行");}
}

可以看到和上面那个实现方法是十分相似的。
但是在main方法里却不能创建Runnable实例然后调用start,在Runnable中没有start方法,所以需要搭配Thread来启动线程。

public class Demo2 {public static void main(String[] args) {//创建runnable对象Runnable runnable = new MyRunnable();//创建线程对象,传入runnable对象Thread t = new Thread(runnable);t.start();}
}

在创建thread对象时,将runnable实例传入。
同样 也可以使用匿名内部类:

//实现 Runnable, 重写 run, 使用匿名内部类
public class Demo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable(){@Overridepublic void run() {System.out.println("线程运行");}});t.start();}
}

1.3 使用lambda表达式

在实际应用中,使用最多的就是这种方法:

    //使用 lambda 表达式
public class Demo5 {public static void main(String[] args) {//使用 lambda 表达式创建线程对象Thread t = new Thread(() ->{System.out.println("线程运行");});t.start();}
}

2.线程中断

线程启动之后,如果遇到一些问题,不想让线程继续运行了,就需要停止线程,也就是线程中断。

2.1 使用变量中断线程

创建一个boolean变量,来控制线程的终止:

public class Demo9 {private static boolean flag = true;public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (flag) {System.out.println("子线程运行");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();System.out.println("主线程运行");Thread.sleep(2000);flag = false;System.out.println("让t线程停止");}}

可以观察出,两秒后,flag变为false,子线程终止,同时运行到最后,主线程也终止。

2.2 使用内置的标志位

Thread类中本身就有一个boolean变量,通过调用isInterruptted()方法来判断,如果为false,说明线程并没有中断,如果为Ture,则说明有事件尝试将线程中断。

public class Demo10 {public static void main(String[] args) {Thread t = new Thread(() -> {while (!t.isInterrupted()) {}});}
}

如果直接这样调用,会出现问题,提示t未初始化,这是因为在lambda表达式中,先执行箭头右边的语句,也就是说在t初始化之前我们就执行了t中的方法,所以需要换一种写法:

public class Demo10 {public static void main(String[] args) {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {}});}
}

使用Thread.currentThread()来获取当前线程的引用。
使用interrupt()方法来尝试中断线程

public class Demo10 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});t.start();Thread.sleep(2000);//尝试中断线程t.interrupt();}
}

运行后,发现没有成功中断进程
在这里插入图片描述
这是由于interrupt()可以唤醒正在"sleep"的线程,报错也显示sleep被打断,打断之后判断中断的标志位改成了false,一直满足while的条件,所以循环不会终止,一直运行。
可以这样解决:
在触发异常后break掉while语句

public class Demo10 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {while (!Thread.currentThread().isInterrupted()) {System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();break;}}});t.start();Thread.sleep(2000);//尝试中断线程t.interrupt();}
}

在这里插入图片描述

3.线程等待

由于多线程在运行的时候,是随机进行调度的,有时候一个线程的任务需要等另一个线程结束后,才能进行工作,这个时候就需要进行线程等待了。
线程等待能够将多个线程按照规定的顺序运行。
我们使用join()方法来实现。

public class Demo11 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {//循环运行五次for (int i = 0; i < 5; i++) {System.out.println("线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {break;}}});//运行t.start();System.out.println("主线程运行前");//main线程等待t线程结束t.join();System.out.println("主线程运行后");}}

我们来看看结果:
在这里插入图片描述
可以看到,主线程在等待t运行结束,在t线程运行结束后,主线程开始运行。所以t.join()实际上就是t线程被主线程等待。

我们也可以做到t线程等待main线程:

public class Demo12 {public static void main(String[] args) {// 获取main引用Thread main = Thread.currentThread();Thread t = new Thread( () -> {try {System.out.println("t线程等待中");main.join();System.out.println("t线程运行中");} catch (InterruptedException e) {throw new RuntimeException(e);}});t.start();for (int i = 0; i < 5; i++) {System.out.println("主线程运行中");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

效果:
在这里插入图片描述
可以给join()方法添加一个参数:
在这里插入图片描述
这里的参数表示等待的最大时间(毫秒),如果时间到了,就不进行等待,直接运行。
还可以增加一个参数,表示纳秒,能够更加精确。
在这里插入图片描述
等待时间有一定误差,大概在十毫秒左右

4.线程休眠和获取线程引用

使用sleep()方法实现线程休眠,在上面多次提到,不再赘述
线程引用也在上面体现(Thread.currentThread())。

总结

本篇文章主要介绍了Java中Thread类的一些基本用法和概念,希望能够帮助你们更加理解Java的多线程操作。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词