多线程之线程的创建中断等待 - javaee


前言

本篇介绍有关线程的创建,中断,等待,描述线程状态等操作,如有错误,请在评论区指正,让我们一起交流,共同进步!


文章目录

  • 前言
    • 1. 创建线程
    • 2. 中断线程
    • 3. 等待线程 - join()
    • 4. 线程状态 - 线程的生命周期
  • 总结

本文开始

1. 创建线程

认识多线程代码:

多线程之线程的创建中断等待 - javaee_第1张图片

1.1 创建线程的方式
① 继承Thread类

    static class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("子线程中 run");
        }
    }
    public static void main(String[] args) {
        Thread t = new MyThread();
        //启动线程
        t.start();
    }

认识 start 与 run
start: 系统中创建一个新的线程,新的线程再执行run方法 =》有线程的创建
run: 表示线程的入口方法 =》没有创建一个新的线程,而是在主线程中调用run方法;

② 实现Runnable接口

 static class MyThread2 implements Runnable {
        @Override
        public void run() {
            System.out.println("子线程中的 run");
        }
    }
    public static void main(String[] args) {
         MyThread2 thread2 = new MyThread2();
         Thread t = new Thread(thread2);
         t.start();
    }

③ 匿名内部类实现Thread

 public static void main(String[] args) {
        Thread t = new Thread() {
            @Override
            public void run() {
                System.out.println("子线程中的 run");
            }
        };
        t.start();
    }

④ 匿名内部类实现Runnable接口

    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("子线程中的 run");
            }
        });
        t.start();
    }

⑤ lambda 表达式实现 =》 推荐使用

  public static void main(String[] args) {
        Thread t = new Thread( () -> {
            System.out.println("子线程中的语句");
        });
        t.start();
    }

2. 中断线程

中断线程:使一个线程停止,就是让线程的入口方法run停止(return等操作);

方式1:定义类变量,在主线程中修改类变量让子线程中断(循环中断,线程结束)
执行过程: 下列两个线程(主线程和新创建的线程),重t.start()开始分头执行,新线程执行判断"isQuit" 类变量的真假,为假进入循环执行,与此同时主线程会先执行睡眠代码,执行完毕后再执行修改类变量的操作,此时新线程如果再次判断 “isQuit” 为true 循环条件非真,就会中断循环,结束新线程;

循环判断条件为什么不是定义在类内的局部变量?
lambda表达式访问的限制 =》lambda访问的变量必须是final修饰的变量,或者是在代码中没有改变过的变量;

[注]:lambda表达式可以访问外面的局部变量(变量捕获)
变量捕获的变量必须是“final”修饰的 或者 没有final修饰但代码中没有修改过的变量;

public static boolean isQuit = false;
    public static void main(String[] args) {
        Thread t = new Thread( () -> {
            while (!isQuit) {
                System.out.println("子线程的语句");
                //睡眠,防止线程太快,看不清执行过程
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //修改变量,让子线程终止
        isQuit = true;
    }

方式2: 使用Thread的方法 interrupt
【注】Thread类中内置了一个标志位,方便实现代码,标志位默认为假;

创建的新线程获取标志位使用Thread中的方法:Thread.currentThread().isInterrupted(); => 判断当前线程的中断标志位
currentThread(): 获取当前线程的实例对象
isInterrupted(): 返回当前线程的状态(true或者false)

执行过程:下列两个线程(主线程和新创建的线程),重t.start()开始分头执行,主线程执行到interrupt(), 使用interrupt将获取到的标志位并改为true,此时创建的线程t, 在执行循环的时候,循环条件判断 !true 新线程就会中断;
interrupt 方法的作用:
① 设置标志为 true;
② 线程正在阻塞状态,此时会把阻塞状态(产生阻塞状态像sleep,wait等)唤醒,通过抛出异常的方式让sleep(阻塞状态) 立即结束;
③ 使用interrupt()方法不会让线程立即结束,只是让线程知道自己该结束了,这些代码控制是灵活的;

【注】sleep被唤醒,此时sleep会自动把isInterrupted的标志位清空(true =》false)就是更改标志位状态;=》sleep被唤醒做的两个事情:抛出异常 + 清空标志位

   public static void main(String[] args) {
        Thread t = new Thread( () -> {
            while (Thread.currentThread().isInterrupted()) {
                System.out.println("子线程的语句");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break; // 为了让循环结束设置break;
                    //不设置break,抛完异常循环还会执行,并不会结束
                }
            }
        });
        t.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //interrupt(): 用来设置标志位
        t.interrupt();
    }

3. 等待线程 - join()

1.为什么需要线程等待呢?
线程之间是并发执行的,线程之间的调度是无序的,随机的,让多个线程执行的先后顺序无法确定;

由此就可以使用 join()方法来解决
2.join() 等待方法两种:
①join():无参一直等待
②join(最大等待的时间):等待最长时间自己可以指定

等待执行过程:
有线程A,B,在线程B中调用join()方法,会让B线程等待,A线程执行结束后,再执行A线程;=》那个线程中调用join()方法,那个线程就等待别的线程,等别的线程执行结束后再执行调用等待的那个线程;
例如:
在主线程中调用t.join() 会阻塞主线程(让主线程等待),等新线程执行结束,主线程才会继续向下执行;

如下代码:如果线程等待,结果一定是先打印"run 中的打印", 在打印"主线程中的main";如果没有线程等待,两者顺序就不确定;

public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread( () -> {
            System.out.println("run 中的打印");
        });
        t.start();
        //主线程中执行的代码
        t.join();//线程等待
        System.out.println("主线程中的main");
    }

4. 线程状态 - 线程的生命周期

线程的6种状态:
① New :系统中线程还没有创建出来,只有Thread对象 - 初始化状态
② RUNNABLE:就绪状态;(正在CPU运行的状态或者准备在CPU上运行的状态) - 运行状态
③ TERMINATED(terminated):线程结束状态,Thread对象还存在;- 终止状态
④ TIMED_WAITING(timed_waiting):时间等待状态;(sleep方法等) - 有时限等待状态
⑤ BlOCKED: 等待锁出现状态;- 阻塞状态
⑥ WAITING:使用wait方法出现的状态 - 无时限等待状态(wait没有参数的情况下,没有notify唤醒会一直等待)

多线程之线程的创建中断等待 - javaee_第2张图片


总结

✨✨✨各位读友,本篇分享到内容如果对你有帮助给个赞鼓励一下吧!!
感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!

你可能感兴趣的:(javaee,java-ee,java,jvm,算法基础,后端)