Thread源码分析之join方法

join方法示例1

源码

import java.util.concurrent.TimeUnit;


public class JoinWaitTest {

    private static int a = 0;
    private static int b = 100;

    public static void main(String... args) throws InterruptedException{
        Thread t = new Thread(new WaitThread());

        t.start();
        t.join();

        System.out.println("I'm waiting for WaitThread end.");
        System.out.println("The result is " + (a + b));
    }

    static class WaitThread implements Runnable {
        @Override
        public void run() {
            try {
                for (int i = 1; i < 6; i++) {
                    TimeUnit.SECONDS.sleep(1);
                    a++;
                    System.out.println(i);
                }
            } catch (InterruptedException e) {

            }
        }
    }
}

执行结果

1html

2java

3编程

4多线程

5app

I'm waiting for WaitThread end.ide

The result is 105oop

场景描述

在不少状况下,主线程生成并启动了子线程,若是子线程里要进行大量的耗时的运算,主线程每每将于子线程以前结束,可是若是主线程处理完其余的事务后,须要用到子线程的处理结果,也就是主线程须要等待子线程执行完成以后再结束,这个时候就要用到join()方法了。源码分析

本例只是个示例,演示的就是上述的过程。this

join方法示例2

源码

import java.util.concurrent.TimeUnit;


public class JoinTest {

    public static void main(String... args) throws InterruptedException {
        Thread jt = new Thread(new JoinThread());
        Thread tt = new Thread(new TimingThread());

        tt.start();
        tt.join();
        jt.start();

    }

    static class JoinThread implements Runnable {
        @Override
        public void run() {
            System.out.println("I have waited for too long.");
        }
    }

    static class TimingThread implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 6; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("Sleep end!");
                } catch (InterruptedException e) {

                }
            }
        }
    }
}

执行结果

Sleep end!spa

Sleep end!

Sleep end!

Sleep end!

Sleep end!

Sleep end!

I have waited for too long.

场景描述

跟源码示例1大同小异,只不过此次是jt线程要等待tt线程结束。

join不带参数源码分析2--必须在同步方法/同步代码块中调用wait方法------为何wait()【还有notify(),notifyAll()】必须在同步方法/代码块中调用

    在 Java中,全部对象都可以被做为"监视器monitor"——指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity。

  全部对象的非同步方法都可以在任意时刻被任意线程调用,此时不须要考虑加锁的问题。

  而对于对象的同步方法来讲,在任意时刻有且仅有一个拥有该对象独占锁的线程可以调用它们。例如,一个同步方法是独占的。若是在线程调用某一对象的同步方法时,对象的独占锁被其余线程拥有,那么当前线程将处于阻塞状态,并添加到对象的入口队列中。

    只有在调用线程拥有某个对象的独占锁时,才可以调用该对象的wait(),notify()和notifyAll()方法。若是尝试在未获取对象锁时调用这三个方法,那么你将获得一个"java.lang.IllegalMonitorStateException:current thread not owner"。

    当一个线程正在某一个对象的同步方法中运行时调用了这个对象的wait()方法,那么这个线程将释放该对象的独占锁并被放入这个对象的等待队列,(JZ:意味着其余线程也能够再次调用同一个对象的wait方法)

  注意,wait()方法强制当前线程释放对象锁。这意味着线程在调用某对象的wait()方法以前,当前线程必须已经得到该对象的锁。所以,线程必须在某个对象的同步方法或同步代码块中才能调用该对象的wait()方法。wait方法是native方法,里面的实现细节不清楚,可是线程A调用某对象B的wait方法确定默认线程A已经拥有了某对象B的锁(可以进入同步方法或同步代码块就说明线程A竞争到了对象锁)。若是跟这种默认(竞争获得锁)冲突,那么JVM就会报出运行时错误IllegalMonitorStateException(RuntimeException)

  当某线程调用某对象的 notify()或notifyAll()方法时,任意一个(对于notify())或者全部(对于notifyAll())在该对象的等待队列中的线程,将被转移到该对象的入口队列。接着这些队列(译者注:可能只有一个)将竞争该对象的锁,最终得到锁的线程继续执行。

若是没有线程在该对象的等待队列中等待得到锁,那么notify()和notifyAll()将不起任何做用。在调用对象的notify()和notifyAll()方法以前,调用线程必须已经获得该对象的锁。所以,必须在某个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法。

  对于处于某对象的等待队列中的线程,只有当其余线程调用此对象的notify()或notifyAll()方法时才有机会继续执行。

  调用wait()方法的缘由一般是,调用线程但愿某个特殊的状态(或变量)被设置以后再继续执行。调用notify()或notifyAll()方法的缘由一般是,调用线程但愿告诉其余等待中的线程:"特殊状态已经被设置"。这个状态做为线程间通讯的通道,它必须是一个可变的共享状态(或变量)。

例如,生产者线程向缓冲区中写入数据,消费者线程从缓冲区中读取数据。消费者线程须要等待直到生产者线程完成一次写入操做。生产者线程须要等待消费者线程完成一次读取操做。假设wait(),notify(),notifyAll()方法不须要加锁就可以被调用。

此时消费者线程调用wait()正在进入状态变量的等待队列(译者注:可能还未进入)。在同一时刻,生产者线程调用notify()方法打算向消费者线程通知状态改变。那么此时消费者线程将错过这个通知并一直阻塞。所以,对象的wait(),notify(),notifyAll()方法必须在该对象的同步方法或同步代码块中被互斥地调用。

[JZ]:这也是多线程编程里的一个经典问题,线程A进行锁操做的过程是非原子的,线程B就进行了释放的请求,致使线程A申请锁后没法释放!

参考网页

http://www.cnblogs.com/jiangz222/p/4719671.html

http://www.blogjava.net/freeman1984/archive/2011/10/14/361306.html

join方法源码分析

jdk源码

/**

     * Waits at most {@code millis} milliseconds for this thread to

     * die. A timeout of {@code 0} means to wait forever.

     *

     * <p> This implementation uses a loop of {@code this.wait} calls

     * conditioned on {@code this.isAlive}. As a thread terminates the

     * {@code this.notifyAll} method is invoked. It is recommended that

     * applications not use {@code wait}, {@code notify}, or

     * {@code notifyAll} on {@code Thread} instances.

     *

     * @param  millis

     *         the time to wait in milliseconds

     *

     * @throws  IllegalArgumentException

     *          if the value of {@code millis} is negative

     *

     * @throws  InterruptedException

     *          if any thread has interrupted the current thread. The

     *          <i>interrupted status</i> of the current thread is

     *          cleared when this exception is thrown.

     */

    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;

            }

        }

}

join不带参数源码分析1--实质上是调用了wait方法

join()方法实质上就是join(0),最终执行代码以下所示

实质上调用代码1就至关于调用代码2

join带参数源码分析

核心代码

变一下:

while (isAlive()) {

            if (millis <= now) {

                break;

            }

            wait(millis - now);

            now = System.currentTimeMillis() - base;

        }

分析

base和now都是时间。base是刚执行代码时的时间,now是执行代码流逝的时间。判断mills时间是否流逝完毕,流逝完毕则break跳出代码。

相关文章
相关标签/搜索