zoukankan      html  css  js  c++  java
  • 006 线程中的join方法

    一 . 概述

    join方法的核心作用就是:

      当前线程等待子线程结束.

    我们可以看到方法的重载,其实就是调用的线程等待子线程多少时间.

    如果不传参数,默认为子线程完成之后才运行.


    二 . 测试用例

    public class JoinClass {
        
        public static void main(String[] args) {
            //创建一个线程,打印1到1000.
            Thread thread = new Thread() {
                @Override
                public void run() {
                    print();
                }
            };
            //开启线程
            thread.start();
          // 加入子线程join ,那么主线程就会等待子线程完成任务.
          thread.join();
    //主线程也做同样的操作 print(); } public static void print() { for(int i = 0 ; i<1000;i++) System.out.println(Thread.currentThread().getName() + " running .... i="+i); } }

    现在我们创建了一个任务,打印1到1000,主线程和一个子线程分别进行.

    打印的效果就是主线程和子线程不断切换运行状态.

    当我们在原先的代码加入一行.

    看红色的部分,此时主线程就会等待子线程完成任务之后再去执行print()方法.


    三 .分析

      一旦加入了红色部分的代码之后,那么主线程就会阻塞自己,直到子线程完成自己的任务之后才会被唤醒.

        因此,thread.join()方法一定要在print()方法之前,否则就不会在主线程开始任务就开始阻塞.

     [理解 ]:

      我们可以认为join()方法是一个将当前线程自我阻塞的方法,直到等待的线程完成之后才会运行.


     四 . 永无止尽的循环 

    public class ForeverThread {
        
        public static void main(String[] args) throws Exception {
            // 主线程等待自己结束才会开始自己的任务...
            Thread.currentThread().join();
        }
    }

    上面的代码中,主线程一直在等待主线程自己运行结束.

      而主线程一直又在等待自己运行结束.

      那么就会出现一个循环.

            等待

        主线程--- ------> 主线程

            等待

    如上,主线程自己就能将自己锁定,一直都无法结束掉.


    五 . 一个例子 

      

    public class TaskThread {
        public static void main(String[] args) throws Exception {
            long startTime = System.currentTimeMillis();
            Thread t1 = new Thread(new Task("task1",1));
            Thread t2 = new Thread(new Task("task2",2));
            Thread t3 = new Thread(new Task("task3",3));
            t1.start();
            t2.start();
            t3.start();
            t1.join();
            t2.join();
            t3.join();
            long endTime = System.currentTimeMillis();
            System.out.println("main thread is done,spned time is = " + (endTime - startTime));
        }
        
    }
    
    class Task implements Runnable{
        //任务的名字
        private final String taskName;
        //任务花费的时间
        private final long costTime;
        public Task(String taskName ,long costTime) {
            this.taskName = taskName ; 
            this.costTime = costTime;
        }
        
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(costTime);
                System.out.println("任务 name = " + taskName + "完成了...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }

    我们创建了一个线程任务类,其中需要传入一个任务的名字,一个线程需要花费的时间.

    在主线程之中,我们创建了三个线程,分别启动之后,使用join.现在运行的结果为: 

    任务 name = task1完成了...
    任务 name = task2完成了...
    任务 name = task3完成了...
    main thread is done,spned time is = 3002

      这个比较好理解: 主线程会在花费时间最长的线程结束之后终结自己.

    下面我们调整一下代码的运行顺序:

      

        t1.start();
            t1.join();
            t2.start();
            t2.join();
            t3.start();
            t3.join();

    现在是1线程首先运行,然后主线程等待1线程结束,然后再开启2线程,如此反复.

      那么,这个方法实际上就相当于一个序列化的运行方式进行着,就是在排队.

    通过这个例子:

      我们知道join就是在阻塞自己,等待阻塞自己的任务结束之后才会运行自己.

  • 相关阅读:
    Lucene:(一)建立索引文件:2。建立索引文件(一)
    Lucene:(一)建立索引文件:2。建立索引文件(二)Segment文件
    92.外边距设置 Walker
    99.元素居中及样式重置 Walker
    94.外边距踩坑 Walker
    101.列表属性 Walker
    97.boxsizing属性 Walker
    98.溢出隐藏 Walker
    95.内边距设置 Walker
    96.内边距和边框踩坑 Walker
  • 原文地址:https://www.cnblogs.com/trekxu/p/8970459.html
Copyright © 2011-2022 走看看