• java多线程之守护线程以及Join方法


    版权声明:本文出自汪磊的博客,转载请务必注明出处。

    一、守护线程概述及示例

    守护线程就是为其它线程提供"守护"作用,说白了就是为其它线程服务的,比如GC线程。

    java程序中线程分两种:用户线程与守护线程,用户线程就是我们平常编写的一个个子线程,比如负责下载的线程,上传数据的线程等。如果一个线程调用了setDaemon(true)方法则变成了守护线程,两种线程本质上没什么区别,但是当一个工程中所有用户线程都执行完了,那么守护线程就没什么服务对象了,此时虚拟机退出,守护线程被销毁。

    下面通过一个小Demo示例。编写DaemonThread类,如下:

     1 public class DaemonThread extends Thread {
     2 
     3     @Override
     4     public void run() {
     5         
     6         while(true){
     7             try {
     8                 Thread.sleep(1000);
     9                 System.out.println("我是线程"+Thread.currentThread().getName()+"我正在执行");
    10             } catch (Exception e) {
    11                 //
    12                 e.printStackTrace();
    13             }
    14         }
    15     }
    16 }

    很简单,在DaemonThread的run方法中先让线程休眠一秒钟,然后打印一下信息,接下来看下main中逻辑:

     1 public static void main(String[] args) {
     2         //
     3         DaemonThread d1 = new DaemonThread();
     4         d1.setDaemon(true);
     5        d1.start();
     6         
     7         for(int i=0;i<500;i++){
     8             System.out.println("我是线程"+Thread.currentThread().getName()+"我正在执行:"+i);
     9        }
    10 }

    主要逻辑就是调用setDaemon方法将d1线程设置为守护线程,主线程中循环打印信息。运行打印如下信息:

      1 我是线程main我正在执行:0
      2 我是线程main我正在执行:1
      3 我是线程main我正在执行:2
      4 我是线程main我正在执行:3
      5 我是线程main我正在执行:4
      6 我是线程main我正在执行:5
      7 我是线程main我正在执行:6
      8 我是线程main我正在执行:7
      9 我是线程main我正在执行:8
     10 我是线程main我正在执行:9
     11 我是线程main我正在执行:10
       ....
     12 我是线程main我正在执行:96
     13 我是线程main我正在执行:97
     14 我是线程main我正在执行:98
     15 我是线程main我正在执行:99

    我们看到只有主线程中信息打印,d1守护线程没有任何信息打印出,原因也很好解释了,运行程序主线程瞬间执行完毕,此时项目中没有其余线程工作,JVM也就退出了,进而d1线程也就得不到执行就被销毁了。守护线程介绍到此为止。

    一、线程join()方法概述及示例

    我所理解的join()的方法主要作用就是"等待"的作用,什么意思呢?比如B线程要等A线程执行完才开始执行其逻辑,那么就可以在B线程即将开始执行其逻辑的时候调用A线程的join()方法,此时就会转到A线程逻辑执行,执行完继续回来执行B线程逻辑,记住:要想join()方法起作用,A线程此时必须是alive状态(源码中有体现)。

    直接看Demo吧.

    JoinThread1类:很简单就是打印信息

     1 public class JoinThread1 extends Thread {
     2 
     3     @Override
     4     public void run() {
     5         
     6         try {
     7             int nextInt = new Random().nextInt(5);
     8             Thread.sleep(nextInt * 1000);
     9             System.out.println("我是线程"+Thread.currentThread().getName()+"我睡了"+nextInt+"秒");
    10         } catch (InterruptedException e) {
    11             e.printStackTrace();
    12         }
    13     }
    14 }

    JoinThread2类:

     1 public class JoinThread2 extends Thread {
     2     
     3     private Thread mThread;
     4     
     5     public JoinThread2(Thread mThread) {
     6         super();
     7         this.mThread = mThread;
     8     }
     9 
    10     @Override
    11     public void run() {
    12         
    13         try {
    14           mThread.join();
    15             int nextInt = new Random().nextInt(5);
    16             Thread.sleep(nextInt * 1000);//sleep在同步的方法中是不释放对象锁的,只有同步方法执行完毕,其他线程才可以执行。
    17             System.out.println("我是线程"+Thread.currentThread().getName()+"我睡了"+nextInt+"秒");
    18             
    19         } catch (InterruptedException e) {
    20             e.printStackTrace();
    21         }
    22     }
    23 }

    初始化的时候传进来一个mThread,在run方法执行的时候首先调用传递进来的mThread的join()方法然后在执行其逻辑。

    mian方法:

     1 public static void main(String[] args) {
     2         //
     3         try {
     4             JoinThread1 join1 = new JoinThread1();
     5             join1.start();
     6             JoinThread2 join2 = new JoinThread2(join1);
     7             join2.start();
     8             join2.join();//join底层是wait方法,会释放对象锁的
     9         } catch (InterruptedException e) {
    10             e.printStackTrace();
    11         }
    12         System.out.println("我是主线程我执行完毕了");
    13 }

    main方法中逻辑也很简单,主要是初始化线程并启动,但是我们调用了join2.join()方法,所以主线程就要等待join2线程执行完毕才继续往下执行,运行程序输出如下:

    1 我是线程Thread-0我睡了1秒
    2 我是线程Thread-1我睡了0秒
    3 我是主线程我执行完毕了

    如果你理解了上面说的打印信息顺序应该很容易理解。

    但是如果main代码改为如下输出Log是什么样的呢:

    public static void main(String[] args) {
            //
            try {
                JoinThread1 join1 = new JoinThread1();
                join1.start();
                JoinThread2 join2 = new JoinThread2(join1);
                join2.join();//join底层是wait方法,会释放对象锁的
                join2.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我是主线程我执行完毕了");
    }

    改为如下又是什么呢?

     1 public static void main(String[] args) {
     2         //
     3         try {
     4             JoinThread1 join1 = new JoinThread1();
     5             JoinThread2 join2 = new JoinThread2(join1);
     6             join2.start();
     7             join2.join();//join底层是wait方法,会释放对象锁的
     8             join1.start();
     9         } catch (InterruptedException e) {
    10             e.printStackTrace();
    11         }
    12         System.out.println("我是主线程我执行完毕了");
    13 }

    如果你能全部答对那么join()方法你就基本全部理解了,知识点虽小,但是也要认真理解透!!!

    本文到此为止,希望对你有帮助。

  • 相关阅读:
    【luogu P1343 地震逃生】 题解
    【luogu P3931 SAC E#1
    【luogu P3275 [SCOI2011]糖果】 题解
    【luogu P2947 [USACO09MAR]向右看齐Look Up】 题解
    【luogu P1456 Monkey King】 题解
    【luogu P3377 左偏树(可并堆)】 模板
    【luogu P1993 小K的农场】 题解
    Sqlmap注入Base64编码的注入点
    kali高速更新源以及主题修改方法
    DiscuzX3.1搬家全过程
  • 原文地址:https://www.cnblogs.com/leipDao/p/8288772.html
Copyright © 2020-2023  润新知