美文网首页
join方法与yield方法

join方法与yield方法

作者: 大海孤了岛 | 来源:发表于2017-05-10 19:53 被阅读148次

    Join方法

    • 定义:等待被调用的线程结束。具体来说,t.join()表示阻塞调用此方法的线程,直到线程t完成为此,方可继续0。

    • 样例一:计算子线程的运行时间

    public class JoinDemo {
        public static void main(String[] args) throws InterruptedException {
            System.out.println(Thread.currentThread().getName() + ": start");
            long start = System.currentTimeMillis();
            Thread t = new Thread(new MyRunnable());
            t.start();
            //阻塞主线程直到子线程完成
            t.join();
            long end = System.currentTimeMillis();
            System.out.println("子线程花费的时间是:" + (end - start) + "ms");
            System.out.println(Thread.currentThread().getName() + ": end");
        }
    
        static class MyRunnable implements Runnable{
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + ": start");
                for (int i = 0; i < 100000; i ++);
                System.out.println(Thread.currentThread().getName() + ": end");
            }
        }
    }
    
    输出结果:
    main: start
    Thread-0: start
    Thread-0: end
    子线程花费的时间是:3ms
    main: end
    
    • 源码分析

    我们查看join方法的源码如下:

    public final void join() throws InterruptedException {
            join(0);
    }
    

    默认设置时长为0,我们继续查看join(n)方法的源码:

    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");
        }
        //设置时长为0时,会一直阻塞,直到被设置的线程结束
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                //wait方法并不能准确地等待,可能会被唤醒,因此需要多次检查判断
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
    

    我们可以看到它是通过wait(n)方法来保证当前线程的等待。对于上面的例子:main线程调用t.join()时,main线程会获得对象t的锁,然后调用该对象的wait(等待时间),直到该对象唤醒main线程。

    • t.join(delay)方法中,当等待时间达到delay时,不管子线程是否执行完毕,主线程都会继续执行。
    public class JoinDemo {
        public static void main(String[] args) throws InterruptedException {
            System.out.println(Thread.currentThread().getName() + ": start");
            Thread t = new Thread(new MyRunnable());
            t.start();
            //设置等待时间为3s
            t.join(3000);
            System.out.println(Thread.currentThread().getName() + ": end");
        }
    
        static class MyRunnable implements Runnable{
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + ": start");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ": end");
            }
        }
    }
    
    运行结果:
    main: start
    Thread-0: start
    main: end
    Thread-0: end
    

    如上,子线程运行的时间为5s,而主线程设置的等待时间为3s,因此当等待时间达到后,主线程会立即执行。

    Yield方法

    • 定义:使当前线程从执行状态(运行状态)变为可执行状态(就绪状态)。

    • 样例

    public class YieldTest {
    
        public static void main(String[] args) throws InterruptedException {
            System.out.println(Thread.currentThread().getName() + ": start");
            long start = System.currentTimeMillis();
            Thread t = new Thread(new MyRunnable());
            t.start();
            //让出CPU给子线程执行任务,直到结束
            while (Thread.activeCount() > 1)
                Thread.yield();
            long end = System.currentTimeMillis();
            System.out.println("子线程花费的时间是:" + (end - start) + "ms");
            System.out.println(Thread.currentThread().getName() + ": end");
        }
    
        static class MyRunnable implements Runnable{
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + ": start");
                for (int i = 0; i < 100000; i ++);
                System.out.println(Thread.currentThread().getName() + ": end");
            }
        }
    
    }
    
    输出结果:
    main: start
    Thread-0: start
    Thread-0: end
    子线程花费的时间是:3ms
    main: end
    
    • yield方法的操作流程:

    先检测当前是否有相同优先级的线程处于同可运行状态,如有,则把CPU的占有权交给次线程,否则继续运行原来的线程,所以yield()方法称为“退让”,它把运行机会让给了同等级的其他线程。

    • yield方法与sleep方法的区别
    • sleep方法使当前运行中的线程睡眠一段时间,进入不可运行状态,这段时间的长短由程序设定,yield方法使当前线程让出CPU占有权,但让出的时间是不可设定的。
    • sleep 方法允许较低优先级的线程获得运行机会,但yield()方法执行时,当前线程仍处在可运行状态,所以不可能让出较低优先级的线程此时获取CPU占有权。

    相关文章

      网友评论

          本文标题:join方法与yield方法

          本文链接:https://www.haomeiwen.com/subject/fohgtxtx.html