一. 线程生命周期
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();
}
发表回复