join方法与yield方法

2017-05-10  本文已影响148人  大海孤了岛

Join方法

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线程。

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

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

  • sleep方法使当前运行中的线程睡眠一段时间,进入不可运行状态,这段时间的长短由程序设定,yield方法使当前线程让出CPU占有权,但让出的时间是不可设定的。
上一篇 下一篇

猜你喜欢

热点阅读