当前位置:首页 » 《关于电脑》 » 正文

JavaEE 初阶篇-深入了解多线程等待与多线程状态

27 人参与  2024年04月05日 15:55  分类 : 《关于电脑》  评论

点击全文阅读


?博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞?收藏⭐评论✍

文章目录

        1.0 线程等待

        1.1 线程等待 - join() 方法

        1.1.1 main 线程中等待多个线程

        1.1.2 main 线程等待 t2 线程且t2 线程等待 t1 线程

        1.1.3 其他线程阻塞等待 main 线程

        1.1.4 在指定的时间内阻塞等待

        1.2 线程等待 - Thread.sleep() 方法

        2.0 线程状态

        2.1 新建状态 - NEW

        2.2 就绪状态 - Runnable

        2.3 终止状态 -Terminated

        2.4 等待状态 - Waiting

        2.5 超时等待状态 - Time_Waiting

        2.6 阻塞状态 - Blocked

        2.7 线程状态之间的相互转换图


        1.0 线程等待

        在线程编程中,线程等待是指一个线程暂停执行,直到某个条件满足或者其他线程执行完毕后再继续执行。线程等待的方法:join() 方法、Thread.sleep() 方法等等

        1.1 线程等待 - join() 方法

       join() 方法是 Thread 类的一个方法,用于让一个线程等待另一个线程执行完毕。当在一个线程对象上调用 join() 方法时,当前线程会被阻塞,直到被调用的线程执行完毕。

        具体来说,调用 thread.join() 会使当前线程等待 thread 线程执行完毕。如果 thread 线程已经执行完毕,那么 join() 方法会立即返回;如果 thread 线程还在执行,当前线程会被阻塞,直到 thread 线程执行完毕。

代码如下:

public class demo1 {    public static void main(String[] args) throws InterruptedException {        Thread thread = new Thread(()->{            for (int i = 0; i < 1000; i++) {                System.out.println("正在执行 thread 线程");            }        });        thread.start();        thread.join();        System.out.println("执行 main 线程");    }}

        main 线程调用 thread.join() ,就会阻塞 main 线程继续执行,会让 thread 线程执行完毕之后,main 线程解除阻塞,继续执行下去。

运行结果:

补充: main 中调用 join() 方法,有以下可能性:

        1.0 如果 t 线程此时已经结束了,此时 join() 方法就会立即返回。

        2.0 如果 t 线程此时还没有结束,此时 main 就会阻塞等待,一直等待到 t 线程结束之后,main 线程才会接触阻塞,继续执行。

        3.0 如果调用等待阻塞的线程对象还没创建 pcb 的时候(即还没 start() 的时候),那么调用 join() 方法的线程会直接解除阻塞。

        1.1.1 main 线程中等待多个线程

        在 main 线程中多次调用 join() 方法时,先执行 t1.join(),如果 t1 还没结束,main 继续阻塞等待,t1 结束之后,继续执行 t2.join() 方法,再等待 t2 结束。注意,t1 与 t2 之间同样是抢占式执行随机调度,所以先后顺序对于 main 线程来说没有什么区别。

代码如下:

public class demo2 {    public static void main(String[] args) throws InterruptedException {        Thread t1 = new Thread(()->{            for (int i = 0; i < 5; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                System.out.println("正在执行 t1 线程");            }        });        Thread t2 = new Thread(()->{            for (int i = 0; i < 5; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                System.out.println("正在执行 t2 线程");            }        });        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println("正在执行 main 线程");    }}

运行结果:

        1.1.2 main 线程等待 t2 线程且t2 线程等待 t1 线程

        这种情况是按顺序执行的,大致就是串行执行一样。顺序为:先要执行完 t1 再执行 t2 最后再执行 main 线程。

代码如下:

public class demo3 {    public static void main(String[] args) throws InterruptedException {        Thread t1 = new Thread(()->{            for (int i = 0; i < 5; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                System.out.println("正在执行 t1 线程");            }        });        Thread t2 = new Thread(()->{            try {                t1.join();            } catch (InterruptedException e) {                throw new RuntimeException(e);            }            for (int i = 0; i < 5; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                System.out.println("正在执行 t2 线程");            }        });        t1.start();        t2.start();        t2.join();        System.out.println("执行 main 线程");    }}

        t1.start() 立即创建 t1 线程,再 t2.start() 创建线程,t1 没有任何阻塞就会直接执行代码,而 t2 遇到了阻塞,需要等待 t1 执行完毕之后,t2 才会解除阻塞,同时由于 main 线程阻塞了,需要等待 t2 执行完毕,当 t2 执行完毕之后,main 线程解除阻塞了,执行 main 线程中的代码。

运行结果:

        1.1.3 其他线程阻塞等待 main 线程

        t1 线程阻塞等待 main 线程执行完毕之后,再执行 t1 线程。

代码如下:

public class demo4 {    public static void main(String[] args) throws InterruptedException {        //拿到当前 main 线程对象        Thread mainThread = Thread.currentThread();        Thread t1 = new Thread(()->{            //在 t1 线程中调用 join() 方法,            //阻塞当前 t1 线程,等待 main 线程执行完毕            try {                mainThread.join();            } catch (InterruptedException e) {                throw new RuntimeException(e);            }            for (int i = 0; i < 5; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                System.out.println("正在执行 t1 线程");            }        });        t1.start();        for (int i = 0; i < 5; i++) {            Thread.sleep(1000);            System.out.println("正在执行 main 线程");        }    }}

运行结果:

        1.1.4 在指定的时间内阻塞等待

        join() 方法还有一个重载的版本,可以指定一个超时时间,即 join(long millis),表示当前线程最多等待 millis 毫秒,如果超过这个时间 thread 线程还没有执行完毕,当前线程会继续往下执行。简单来说,即使 thread 这个线程还没有结束,main 线程都不会继续等待了;如果 thread 在规定的时间内提前结束,那么 main 也会提前解除阻塞。

代码如下:

public class demo5 {    public static void main(String[] args) throws InterruptedException {        Thread thread = new Thread(()->{            for (int i = 0; i < 1000; i++) {                System.out.println("正在执行 thread 线程");            }        });        thread.start();        //等待 0.1 s 就解除阻塞 main 线程,即不会继续等待了        thread.join(1000);        System.out.println("正在执行 main");    }}

运行结果:

        1.2 线程等待 - Thread.sleep() 方法

        是一个静态方法,它使当前线程暂停执行一段时间。该方法接受一个以毫秒为单位的时间参数,指定线程暂停的时间长度。在这段时间内,线程不会执行任何操作,但是线程的状态仍然是 Runnable 状态,可以随时被调度器调度执行。

        需要注意的是,Thread.sleep() 方法不是真正意义上的线程等待,它只是让线程暂停执行一段时间,不会释放锁或资源。在实际开发中,应根据具体需求选择合适的线程等待机制,以确保程序的正确性和效率。

代码如下:

public class demo6 {    public static void main(String[] args) {        Thread thread = new Thread(()->{            for (int i = 0; i < 5; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }                System.out.println("正在执行 thread 线程");            }        });        thread.start();            }}

运行结果:

        每相隔 1 秒就会输出一次。

        需要注意的是,这里的 Thread.sleep() 方法是受查异常,且 run() 是重写父类的方法,该 run() 方法的方法名、参数列表、声明异常都需要与父类保持一致,因此这里不能声明异常,只能捕获异常处理。

        2.0 线程状态

        在 Java 中主要包括六种不同的状态。

        2.1 新建状态 - NEW

        当创建一个线程对象时,线程处于新建状态,此时线程对象已经创建好了,但是还没调用 start() 方法启动线程,因此线程还没被创建出来。

        2.2 就绪状态 - Runnable

        有两种情况都属于就绪状态:1)还没运行,就绪状态。但是线程已经准备好运行了,只等待被 CPU 调度执行。2)线程正在被 CPU 调度执行中,运行状态。总而言之,无论是就绪状态还是运行状态在 Java 中都属于 Runnable 状态,即就绪状态。

        2.3 终止状态 -Terminated

        线程执行完任务后或者出现异常导致线程终止时,线程进入终止状态。在终止状态下,线程不再执行任务。

        2.4 等待状态 - Waiting

        线程进入等待状态通常时因为调用了 thread.join() 方法等等。

代码如下:

public class demo7 {    public static void main(String[] args) throws InterruptedException {        Thread thread = new Thread(()->{            while (true){                System.out.println(1);            }        });        thread.start();        thread.join();        System.out.println("正在执行 main 线程");    }}

演示线程等待:

        main 线程调用了 thread.join() 方法阻塞等待 thread 线程,又因为 thread 还当前为止还没结束, 所以当前 main 线程被阻塞了,因此 main 状态为 Waiting 状态。对于 thread 线程来说,目前的状态为 Runnable 状态。

        2.5 超时等待状态 - Time_Waiting

        线程调用带有超时参数的等待方法,比如 Thread.sleep(long millis) 等待方法。线程会进入超时等待状态下,线程会等待一段时间后自动恢复到就绪状态。

代码如下:

public class demo8 {    public static void main(String[] args) {        Thread thread = new Thread(()->{            try {                Thread.sleep(9000000);            } catch (InterruptedException e) {                throw new RuntimeException(e);            }            System.out.println("正在执行 thread 线程");        });        thread.start();        System.out.println("正在执行 main 线程");    }}

演示超时等待:

        2.6 阻塞状态 - Blocked

        线程在特定情况下,会进入阻塞状态,比如调用了 Thread.sleep() 方法或者加锁。在线程阻塞状态下,线程暂时停止执行,直到满足特定条件后,才能继续执行。

代码如下:

死锁状态:两个线程两把锁

public class demo10 {    public static void main(String[] args) {        Object o1 = new Object();        Object o2 = new Object();        Thread t1 = new Thread(()->{           synchronized (o1){               try {                   Thread.sleep(1000);               } catch (InterruptedException e) {                   throw new RuntimeException(e);               }               synchronized (o2){                   System.out.println("正在执行 t1 线程");               }           }        });        Thread t2 = new Thread(()->{           synchronized (o2){               try {                   Thread.sleep(1000);               } catch (InterruptedException e) {                   throw new RuntimeException(e);               }               synchronized (o1){                   System.out.println("正在执行 t2 线程");               }           }        });        t1.start();        t2.start();    }}

演示阻塞状态:

        2.7 线程状态之间的相互转换图


点击全文阅读


本文链接:http://zhangshiyu.com/post/90826.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1