• 一篇文章带你理解Thread(多线程)的基础用法


    目录

    1.线程创建

    1.1通过继承类创建

    1.2通过类实现接口创建

    1.3通过内部类继承Thread来创建

    1.4通过内部类实现Runnable接口来创建

    1.5通过lambda表达式创建

    2.线程中断

    2.1自定义标志位

    2.2interrupt()方法

    3.线程等待

    4.线程休眠

    5.获取线程实例


    1.线程创建

            线程创建有五种方法,这里喜欢用那种用那种

    注意:下文中的start方法才是多线程开始执行,run方法只是表明需要执行的内容

    1.1通过继承类创建

    1. class A extends Thread {
    2. @Override
    3. public void run() {
    4. System.out.println("通过继承Thread类创建线程");
    5. }
    6. }
    7. public class Main {
    8. public static void main(String[] args) {
    9. A a = new A();
    10. //这里的start是线程开始执行的方法,执行的是Thread中的run方法
    11. a.start();
    12. }
    13. }

    这里需要注意,当我们继承Thread类的时候,必须重新run方法,相当于是在给线程分配任务

    1.2通过类实现接口创建

    1. class B implements Runnable{
    2. @Override
    3. public void run() {
    4. System.out.println("通过实现Runnable接口来创建");
    5. }
    6. }
    7. public class Main {
    8. public static void main(String[] args) {
    9. //这里通过Thread类型对象,对构造方法传入一个实现了Runnable接口的类来创建
    10. Thread b = new Thread(new B());
    11. b.start();
    12. }
    13. }

    1.3通过内部类继承Thread来创建

    1. public class Main {
    2. public static void main(String[] args) {
    3. Thread c = new Thread(){
    4. @Override
    5. public void run() {
    6. System.out.println("通过匿名内部类继承Thread来创建");
    7. }
    8. };
    9. c.start();
    10. }
    11. }

    1.4通过内部类实现Runnable接口来创建

    1. public class Main {
    2. public static void main(String[] args) {
    3. Thread d = new Thread(new Runnable() {
    4. @Override
    5. public void run() {
    6. System.out.println("通过匿名内部类实现Runnable接口来实现");
    7. }
    8. });
    9. d.start();
    10. }
    11. }

    1.5通过lambda表达式创建

    1. public class Main {
    2. public static void main(String[] args) {
    3. Thread e = new Thread(()-> System.out.println("使用lambda表达式创建"));
    4. e.start();
    5. }
    6. }

    最后我们看一下所有的执行结果

    总结:

    可以发现,只有通过继承Thread类的时候,不需要创建Thread对象,其余的都需要创建Thread对象

    2.线程中断

    2.1自定义标志位

    这种方法很简单,就是自己定义一个变量,用来标识线程结束,当执行某条语句,则线程结束,就不进行演示了

    2.2interrupt()方法

    不仅可以用自定义的标志位,我们还可以调用interrupt方法,来进行线程中断

    1. public class Main {
    2. public static void main(String[] args) throws InterruptedException {
    3. Thread t1 = new Thread(() -> {
    4. //通过Thread.interrupted()判断是否存在标志位,若不存在则一直执行while,若存在则停止并且清除标志位
    5. while(!Thread.interrupted()){
    6. System.out.println("123");
    7. }
    8. });
    9. t1.start();
    10. Thread.sleep(1);
    11. //通过t1.interrupt()创建标志位
    12. t1.interrupt();
    13. }
    14. }

    上述代码中的含义是,开始没标志位,所以while语句可以一直执行,当我们执行到t1.interrupt之后,创建了一个标志位,这样我们就拥有了标志位,所以while循环就会终止,代码的运行结果如下

    可以看到我们的线程是有停止的

     我们总结一些常用的标志位用法

    1.Thread.interrupt()       设置标志位,若线程阻塞则抛出异常,并且清除标志位

    2.Thread.interrupted()     判断是否有标志位,若存在返回true,否则返回false,最后清除标志位 

    3.Thread..currentThread().isInterrputed()      判断是否有标志位,若存在返回true,否则返回false,最后不清除标志位 

    第三个个currentThread是得到当前线程的引用,通过这个引用再去调用isInterrputed方法

     

    可以看到,isInterrupted方法是线程实例中的方法,不是类方法,所以我们需要通过引用来调用

    3.线程等待

    在多线程中,一个线程等待另一个线程,通常使用jion()方法

    1. public class Main {
    2. public static void main(String[] args) throws InterruptedException {
    3. Thread t1 = new Thread(() -> {
    4. for (int i = 0; i < 10; i++) {
    5. System.out.println("别急,我还没结束呢");
    6. }
    7. System.out.println("我结束了");
    8. });
    9. t1.start();
    10. t1.join();
    11. System.out.println("你终于结束了");
    12. }
    13. }

    看这段代码,就是让主线程去等待t1线程,就是通过调用t1的join()方法来实现的,看一下运行结果

    可以看到,当我们的主线程走到t1.join()之后,进行了阻塞等待,然后等t1执行结束了,才开始执行主线程后面的内容,这就是线程的等待

    4.线程休眠

    线程休眠我们通常使用sleep方法,这个方法是存在于Thread中的类方法,需要传入一个参数,单位是毫秒,就是让当前线程阻塞等待多长时间之后,再执行,看具体实现

    1. public class Main {
    2. public static void main(String[] args) throws InterruptedException {
    3. Thread t1 = new Thread(() -> {
    4. for (int i = 0; i < 1000; i++) {
    5. System.out.println("别急,我还没结束呢");
    6. }
    7. System.out.println("我结束了");
    8. });
    9. t1.start();
    10. Thread.sleep(1);
    11. System.out.println("============================================================");
    12. }
    13. }

    看这样一段代码,我们让主线程一秒后打印一串'=',当我们运行线程的时候

    可以看到,主线程等待一秒后,打印了=,但是t1并未执行结束,但是我们的主线程调用的是sleep方法,所以并不会无限制的等下去

    注意:这里的sleep需要处理编译异常,

    InterruptedException

     

    我们可以像上面一样加上声明,也可以使用try{}catch来处理,这个我们在异常的时候已经说过了,就不再赘述了

     

    5.获取线程实例

    这里我们使用currentThread来获取线程的实例,这里和this有异曲同工之妙,在哪里调用的,就会获取到哪个实例,看代码实现

    1. public class Main {
    2. public static void main(String[] args) throws InterruptedException {
    3. Thread t1 = new Thread(() -> {
    4. System.out.println(Thread.currentThread());
    5. });
    6. t1.start();
    7. System.out.println(Thread.currentThread());
    8. }
    9. }

    运行结果是这样的

    我们可以看到,在main中的是main线程,t1是Thread-0线程,我们做个测试,如果,在主线程中通过t1来调用currentThread获取到的是哪个线程呢?

    1. public class Main {
    2. public static void main(String[] args) throws InterruptedException {
    3. Thread t1 = new Thread(() -> {
    4. });
    5. t1.start();
    6. System.out.println(t1.currentThread());
    7. }
    8. }

     我们可以看到,我们在主线程中通过t1去调用currentThread()方法,得到结果也是和我们预期的一样

    为什么?

    因为我们的currentThread()是一个静态方法,所以不论你通过什么Thread的实例调用,其实结果都是一样的,只有一个,就是当前线程的引用 

    以上就是多线程的一些基本使用了

            感谢阅读

  • 相关阅读:
    Bean的四种实例化方式以及BeanFactory和FactoryBean的区别
    vue实现全局消息提醒功能(vue-extend)
    华为云云耀云服务器L实例使用教学|Unbelievable, 带你用云服务器部署Windows12
    【PAT甲级】1043 Is It a Binary Search Tree
    Linux fcntl函数
    HarmonyOS鸿蒙-DevEco Studio工具
    linux 配置 NTP 服务器
    Linux基础篇
    TOUGH2系列建模方法及在CO2地质封存、水文地球化学、地热、地下水污染等领域中的实践技术应用
    【PAT甲级】1099 Build A Binary Search Tree
  • 原文地址:https://blog.csdn.net/qq_55546526/article/details/126823909