JAVA源码分析之Thread

sleep(long millis, int nanos)源码:

public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        sleep(millis);
    }

sleep精确到毫秒级,nanos没有用到,只是
1.当nanos大于等于500000
2.millis等于0且nanos不等于0
二者满足至少一个条件的时候,millis++。

sleep(long millis)方法:

public static native void sleep(long millis) throws InterruptedException;

这个方法是一个native方法,即一个原生态的方法,原生态的方法是利用其它语言来实现的。这是因为JAVA是没法和硬件底层打交道。只能委托给其它语言来实现。

run()方法

1.new SubThread().start();
2.new Thread(new SubRunnable).start();

我们调用run()方法是通过调用start()方法间接调用的。

start()方法源码:

public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

从上面的代码可以看出,start()方法主要是调用了一个start0()这个方法。而start0() 是一个原生态方法,如下:

private native void start0();

start0()方法也是native方法,由其他语言实现。

Thread类的run()方法:

由于Thread类是实现Runnable接口。Runable接口中只有一个抽象的run方法,如下:

public abstract void run();

因此,Thread类需要重写run()方法:

@Override
    public void run() {
        if (target != null) {
            target.run();//target是一个Runnable的引用
        }
    }

如果target存在,则执行target的run()方法,否则什么也不做。也就是说Thread的run()方法总是先被调用,然后调用target(构造函数中的Runnable对象)的run()方法。

join(long millis)方法:

join方法有几种重载形式,但是,最终都是调用此函数,因此,下面就对其进行介绍。

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;
            }
        }
    }

这段源码前面对这个函数的介绍如下:

Waits at most {@code millis} milliseconds for this thread to die. A timeout of {@code 0} means to wait forever.

字面意思就是:等待millis毫秒直到这个线程死亡。但是这个线程到底是指的是子线程还是主线程呢???

下面举几个例子就知道答案了。

public class TestThread_v1 extends Thread {
	public static void main(String[] args) {
		Thread t=new TestThread_v1();
		t.start();
		try {
			t.join(1000);//main线程只等待1000ms
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("main end");
	}

	@Override
	public void run() {
		super.run();
		System.out.println("subThread begin");
		try {
			System.out.println("subThread sleep begin");
			Thread.sleep(900);//休眠900毫秒
			System.out.println("subThread sleep end");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("subThread end");
	}
	}

运行结果如下:

    subThread begin
    subThread sleep begin
    subThread sleep end
    subThread end
    main end

即当main线程中调用t.join(mills)时,main线程只等待mills毫秒,当达到时间时,无论子线程是否结束,均不再等待。

下面可以测试下:将子线程 sleep 2000毫秒,如下:

public class TestThread_v1 extends Thread {
	public static void main(String[] args) {
		Thread t=new TestThread_v1();
		t.start();
		try {
			t.join(1000);//main线程只等待1000ms,无论子线程是否结束,均不在等待。
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("main end");
	}

	@Override
	public void run() {
		super.run();
		System.out.println("subThread begin");
		try {
			System.out.println("subThread sleep begin");
			Thread.sleep(2000);//休眠2000毫秒
			System.out.println("subThread sleep end");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("subThread end");
	}	
	}

运行结果如下;

    subThread begin
    subThread sleep begin
    main end //这里就是:main线程等待结束后的输出
    subThread sleep end
    subThread end

当main函数调用的是t.join(),Thread 类中的源码如下:

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

回到这一节开始的源码处,从源码中我们看到join()方法实现是通过wait(Object 中的一个native方法)来实现的。当main线程调用t.join的时候,main线程会获得线程对象t的锁(wait意味着拿到了该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程,比如子线程退出等。

这就意味着main线程调用t.join()时,必须要拿到线程t对象的锁,如果拿不到的话它是无法wait的,刚开始的例子中t.join(1000)不是说明了main线程等待1s,如果在它等待之前,其它线程获得了t对象的锁,它等待的时间就可不就是1s了。

看如下测试代码:

package com.wrh.threadInterrupt;

public class TestThread_v1 extends Thread {

	public static void main(String[] args) {
		Thread t=new TestThread_v1();
		Thread t1=new SubThread(t);
		t1.start();//这个子线程会先持有线程t的锁
		t.start();
		try {
			//main线程只等待1000ms,无论子线程是否结束,均不在等待。,但是其等待的前提条件时要持有线程t的锁
			t.join(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("main end");
	}

	@Override
	public void run() {
		super.run();
		System.out.println("sub  Thread begin");
		try {
			System.out.println("sub  Thread sleep begin");
			Thread.sleep(800);//休眠800毫秒
			System.out.println("sub  Thread sleep end");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("subThread end");
	}	
	}
	class SubThread extends Thread{
	Thread thread;
	public SubThread(Thread t){
		this.thread=t;
	}
	@Override
	public void run() {
		super.run();
		holdThreadLock(thread);
	}
	private void holdThreadLock(Thread thread2) {
		synchronized (thread2) {
			System.out.println("hold Thread lock");
			try {
				Thread.sleep(3000);//休眠3000毫秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("release Thread lock");
		}
	}
	
}

在main方法中,通过Thread t1=new SubThread(t);t1.start();开启另一个子线程,这个子线程它在holdThreadLock()方法中,通过synchronized(thread2)来获取线程对象t的锁,并在sleep(3000)后释放,这就意味着,即使在main方法中t.join(1000),等待1000毫秒,但是由于首先是子线程t1获得了子线程t的锁,main无法获取子线程t的锁,因此,他实际的等待时间是3000+1000ms

运行结果如下:

    hold Thread lock
    sub Thread begin
    sub Thread sleep begin
    sub Thread sleep end
    subThread end
    release Thread lock
    main end

猜你喜欢

转载自blog.csdn.net/ssllnn1314/article/details/88959276