Thread中join

阅读:286

目录介绍

  • 01.join方法作用
  • 02.join注意事项
  • 03.join方法实现原理
  • 04.join方法源码
  • 05.经典面试题

01.join方法作用

  • join方法
    • public final void join()
    • 等待该线程执行完毕了以后,其他线程才能再次执行。Thread的非静态方法join()让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。
    • 保证当前线程停止执行,直到该线程所加入的线程完成为止。然而,如果它加入的线程没有存活,则当前线程不需要停止。
  • join()有什么作用?
    • Thread的join()的含义是等待该线程终止,即将挂起调用线程的执行,直到被调用的对象完成它的执行。比如存在两个线程t1和t2,下述代码表示先启动t1,直到t1的任务结束,才轮到t2启动。
    t1.start();
    t1.join(); 
    t2.start();
    

02.join注意事项

  • 注意事项:
    • 在线程启动之后,才能调用调用方法。如果没有启动,调用该方法,则直接会……
  • join与start调用顺序问题
    • join方法必须在线程start方法调用之后调用才有意义。这个也很容易理解:如果一个线程都没有start,那它也就无法同步了。因为执行完start方法才会创建线程。

03.join方法实现原理

  • join方法是通过调用线程的wait方法来达到同步的目的的。例如A线程中调用了B线程的join方法,则相当于在A线程中调用了B线程的wait方法,当B线程执行完(或者到达等待时间),B线程会自动调用自身的notifyAll方法唤醒A线程,从而达到同步的目的。

04.join方法源码

  • 如下所示,由下面的join方法源码可以看到:
    • 1、如果join方法传参为0的话,则会调用isAlive()方法,一直检测线程是否存活(执行完毕),如果存活就调用wait方法,一直阻塞。isAlive()判断线程是否还活着,即线程是否还未终止。
    • 2、如果参数为负数,则直接报错:"timeout value is negative"
    • 3、如果参数大于0,则while里面一直判断线程是否存活,存活的话就一直判断当前线程执行的时间并与计算还需要等待多久时间,最后如果等待时间小于等于0就跳出循环,否则就继续wait
    public final synchronized void join(long millis) throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
    
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
    
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
    

05.经典面试题

  • 经典面试题:现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
    • Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行。当我们调用某个线程的这个方法时,这个方法会挂起调用线程,直到被调用线程结束执行,调用线程才会继续执行。
    /**
     * 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
     */
    private void test2(){
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("线程执行","Thread1");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("线程执行","Thread2");
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("线程执行","Thread3");
            }
        });
    
        t1.start();
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        t2.start();
        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    
        t3.start();
        try {
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    

  • 另一种写法,发现并不是按照t1、t2、t3的执行顺序的。
    /**
     * 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?
     */
    private void test2(){
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("线程执行","Thread1");
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("线程执行","Thread2");
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("线程执行","Thread3");
            }
        });
    
        t1.start();
        t2.start();
        t3.start();
    
    
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    

  • 如果不适用join,还可以用什么方式,使用锁也可以实现。
    private void test3(){
        final ShareThread sh = new ShareThread();
        new Thread(new Runnable() {
    
            @Override
            public void run() {
                try {
                    sh.Test01();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "T1").start();
        new Thread(new Runnable() {
    
            @Override
            public void run() {
                try {
                    sh.Test02();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "T2").start();
        new Thread(new Runnable() {
    
            @Override
            public void run() {
                try {
                    sh.Test03();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "T3").start();
    }
    
    
    class ShareThread {
    
        // flag作为标记
        private int flag = 1;
        private Lock lock = new ReentrantLock();
        private Condition c1 = lock.newCondition();
        private Condition c2 = lock.newCondition();
        private Condition c3 = lock.newCondition();
    
        public void Test01() throws InterruptedException {
            lock.lock();
            try {
                while (flag != 1) {
                    c1.await();
                }
                System.out.println("正在执行的是:" + Thread.currentThread().getName());
                flag = 2;
                c2.signal();// 通知一个线程来执行
            } finally {
                lock.unlock();
            }
        }
    
        public void Test02() throws InterruptedException {
            lock.lock();
            try {
                while (flag != 2) {
                    c2.await();
                }
                System.out.println("正在执行的是:" + Thread.currentThread().getName());
                flag = 3;
                c3.signal();// 通知一个线程来执行
            } finally {
                lock.unlock();
            }
        }
    
        public void Test03() throws InterruptedException {
            lock.lock();
            try {
                while (flag != 3) {
                    c3.await();
                }
                System.out.println("正在执行的是:" + Thread.currentThread().getName());
                flag = 1;
                c1.signal();// 通知一个线程来执行
            } finally {
                lock.unlock();
            }
        }
    }
    


赞赏支持


精彩留言

发表评论