前言
在本栏的上一节(https://blog.csdn.net/2301_80653026/article/details/138500558),我们重点讲解了五种不同的创建线程的方式,我们还介绍了Tread类的常见构造方法和常见属性,在这一节中我们将会继续介绍Tread类。
一、启动一个线程 start( )
在上一节我们讲解了如何通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。比如:
- 覆写 run 方法是提供给线程要做的事情的指令清单
- 线程对象可以认为是把 李四、王五叫过来了
- 而调用 start( ) 方法,就是喊一声:”行动起来!“,线程才真正独立去执行了
调用 start 方法, 才真的在操作系统的底层创建出一个线程。
Thread类中run和start的区别:
作用功能不同:
1. run方法的作用是描述线程具体要执行的任务;
2. start方法的作用是真正的去申请系统线程
.运行结果不同:
1. run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次;
2. start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段
参考示例代码:
/*** @author Zhang* @date 2024/4/2915:16* @Description:*///创建一个类,继承自Thread
class MyThread extends Thread{//这个方法就是线程的入口方法@Overridepublic void run() {// System.out.println("hello Thread");while(true){System.out.println("hello threat");try {Thread.sleep(1000); //休眠1000毫秒/*** 此处必须try catch,不能throws* 在这个代码中重写的是父类的run,父类的run没有throws,因此,子类方法也就不能有throws*/} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}//创建线程
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread t = new MyThread();//start 和run都是Threat的成员//run只是描述了线程的入口(线程要做生么任务)//start 则是真正调用了系统API,在系统中创建线程,让线程再调用runt.start();while(true){System.out.println("hello main");Thread.sleep(1000); //休眠1000毫秒}}
}
二、中断一个线程
停止一个线程主要有以下两种方式:
2.1 通过共享的标记来进行沟通
参考实例代码:
/*** @author Zhang* @date 2024/5/415:58* @Description:*/
public class Demo8 {private static boolean isQuit = false; //成员变量public static void main(String[] args) throws InterruptedException {// boolean isQuit = false; 不能使用局部 变量Thread t= new Thread(()->{while(!isQuit){//System.out.println("线程工作中");//此处的打印可以替换成任意的逻辑来表示逻辑的实际工作内容try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程作完毕");});t.start();Thread.sleep(5000);isQuit = true;System.out.println("设置 isQuit 为 true");}
}
2.2 调用interrupt( )方法来通知
使用 Thread.interrupted() 或Thread.currentThread().isInterrupted() 代替自定义标志位。其中,Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记。
使用 thread 对象的 interrupted() 方法通知线程结束的代码参考实例:
public class ThreadDemo {private static class MyRunnable implements Runnable {@Overridepublic void run() {// 两种方法均可以while (!Thread.interrupted()) {//while (!Thread.currentThread().isInterrupted()) {System.out.println(Thread.currentThread().getName()+ ": 别管我,我忙着转账呢!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();System.out.println(Thread.currentThread().getName()+ ": 有内鬼,终止交易!");// 注意此处的 breakbreak;}}System.out.println(Thread.currentThread().getName()+ ": 啊!险些误了大事");}}
------------------------------------------------------------------public static void main(String[] args) throws InterruptedException {MyRunnable target = new MyRunnable();Thread thread = new Thread(target, "李四");System.out.println(Thread.currentThread().getName()+ ": 让李四开始转账。");thread.start();Thread.sleep(10 * 1000);System.out.println(Thread.currentThread().getName()+ ": 老板来电话了,得赶紧通知李四对方是个骗子!");thread.interrupt();}
}
thread 收到通知的方式有两种:
- 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以InterruptedException 异常的形式,清除中断标志。
当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法, 可以选择忽略这个异常, 也可以跳出循环结束线程
- 否则,只是内部的一个中断标志被设置,thread 可以通过
Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志
/*** @author Zhang* @date 2024/5/416:27* @Description:*/
public class Demo9 {public static void main(String[] args) {Thread t = new Thread(() ->{//Thread类内部,有一个现成的标志位,可以判定当前的循环是否结束while(!Thread.currentThread().isInterrupted()){System.out.println("线程工作中");try {Thread.sleep(1000);} catch (InterruptedException e) {//throw new RuntimeException(e);//1.假装没听见,循环继续正常执行e.printStackTrace();// 2.加上一个break,表示线程立即结束//break;//3.先做一些其他工作,完成之后再结束//其他工作的代码//break;}}});t.start();try {Thread.sleep(5000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("线程终止");t.interrupt();}
}
三、 等待一个线程join( )
有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作
参考实例代码:
/*** @author Zhang* @date 2024/5/416:54* @Description:*/
public class Demo10 {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(()->{for (int i = 0; i<5;i++ ){System.out.println("t 线程工作中");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();//让主线程等待t线程执行结束//一旦调用join,主线程就会出发阻塞。此时t线程就可以趁机完成后续的工作//一直阻塞到 t 执行完毕了, join才会解除阻塞,才能继续执行System.out.println("join 等待开始");t.join();//t.join 工作过程:// 1)如果t线程正在运行中,此时调用 join 的线程就会阻塞, 一直阻塞到t线程执行结束为止// 2)如果t线程已经执行结束了,此时调用 join 线程,就直接返回了,不会涉及到阻塞~~System.out.println("join 等待结束");}
}
其他一些 join( )方法
四、获取当前线程引用 和 休眠当前线程
4.1 获取当前线程引用
常见方法:public static Thread currentThread(); ——返回当前线程对象的引用
参考代码实例
public class ThreadDemo {public static void main(String[] args) {Thread thread = Thread.currentThread();System.out.println(thread.getName());}
}
4.2 休眠当前线程
public class ThreadDemo {public static void main(String[] args) throws InterruptedException {System.out.println(System.currentTimeMillis());Thread.sleep(3 * 1000);System.out.println(System.currentTimeMillis());}
}
五、 线程的状态
总结
好啦!以上就是今天要讲的内容,本文介绍了Thread类的start( )方法、线程的的中断、等待一个线程join( )、获取当前线程的引用,休眠当前线程,以及线程的引用。在本栏的下一节我们将会继续介绍Thread中重点内容——线程安全。