一. 线程生命周期
1. 线程的生命周期包含新建、就绪、运行、阻塞、销毁五中状态
-
新建:应用 new 办法,实例化一个线程
Thread thread = new Thread();
-
就绪:调用 start() 办法后,这时候线程处于期待 CPU 分配资源阶段
调用 yeild() 办法,让出 cpu 资源,程序由运行状态变为就绪状态
当阻塞的状态通过 notify() 和 notifyAll() 办法唤醒当前
thread.start();
- 运行:当就绪的线程获取到 CUP 资源当前, 便进入运行状态
-
阻塞:在运行状态的时候,因为某些起因使线程变成阻塞状态,比方 sleep()、wait()、join()
- sleep() : sleep 状态下线程并不会开释锁
- wait(): 处于 wait 状态下的线程会开释本人获取的锁
- join(): 当线程调用 join 办法后,线程底层会调用 wait() 进入阻塞,join 底层是用 wait() 和 notify() 实现的,待其余线程调用 notify() 或 notifyAll(),线程会进入到就绪状态抢占 cpu 资源
- 销毁:如果线程在失常执行完结或者线程受到强制终止或者受到异样而导致完结,那么线程就会被销毁
2. 这外面有几个办法须要重点解析
-
yield()
- 使以后线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu 会从泛滥的可执行态里抉择,也就是说,以后也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说肯定会执行其余线程而该线程在下一次中不会执行到了。
- 用了 yield 办法后,该线程就会把 CPU 工夫让掉,让其余或者本人的线程执行(也就是谁先抢到谁执行)
- 通过 yield 办法来实现两个线程的交替执行。不过请留神:这种交替并不一定能失去保障。
- yield() 只是使以后线程从新回到可执行状态,所有执行 yield() 的线程有可能在进入到可执行状态后马上又被执行,所以 yield() 办法只能使同优先级的线程有执行的机会
-
join()
在很多状况下,主线程创立并启动子线程,如果子线程中要进行大量的耗时运算,主线程将可能早于子线程完结。如果主线程须要晓得子线程的执行后果时,就须要期待子线程执行完结了。主线程能够 sleep() 进入休眠, 但休眠工夫不好确定,因为子线程的执行工夫不确定,join() 办法比拟适合这个场景。
3. join 调用形式如下所示:
Thread subThread = new Thread(new Runnable() {
@Override
public void run() {// do something}
});
subThread.start();
subThread.join();
// 等子线程 subThread 实现后,主线程被唤醒,接着执行
4. join 底层源码如下所示:
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @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 void join() throws InterruptedException {join(0);
}
底层调用了 join(long millis) 办法:
/**
* 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 的底层是调用了线程的 wait() 办法,当主线程调用了 join() 办法的时候,主线程会获取子线程 subThread 的对象锁,调用该对象的 wait() 办法,而后进入阻塞状态
主线程被唤醒:
那么 t2 是如何被唤醒的呢。因为咱们本人应用的时候都是 wait 和 notify/notifyAll 成对呈现的。否则线程将无限期期待上来。如果期待线程还是一个非守护线程。那么就会导致程序不能失常完结。
// 位于 /hotspot/src/share/vm/runtime/thread.cpp 中
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
// ...
// Notify waiters on thread object. This has to be done after exit() is called
// on the thread (if the thread is the last thread in a daemon ThreadGroup the
// group should have the destroyed bit set before waiters are notified).
// 有一个贼不起眼的一行代码,就是这行
ensure_join(this);
// ...
}
static void ensure_join(JavaThread* thread) {
// We do not need to grap the Threads_lock, since we are operating on ourself.
Handle threadObj(thread, thread->threadObj());
assert(threadObj.not_null(), "java thread object must exist");
ObjectLocker lock(threadObj, thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();
// Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED.
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
// Clear the native thread instance - this makes isAlive return false and allows the join()
// to complete once we've done the notify_all below
java_lang_Thread::set_thread(threadObj(), NULL);
// 同志们看到了没,别的不必看,就看这一句 thread 就是以后线程
lock.notify_all(thread);
// Ignore pending exception (ThreadDeath), since we are exiting anyway
thread->clear_pending_exception();}