java当前线程休眠,什么方法终止时能使线程进入死亡状态
目录
线程生命周期概述线程生命周期流程图线程生命周期测试java中的启动线程Hotspot中的启动线程中断和复位不要用stop方法,用中断方法复位线程,复位其他线程。
Thread生命周期
生命周期概述
Java的线程状态描述放在Thread类的枚举类State中。它总共包含6个状态(从出生到死亡)。公共枚举状态{/** *未启动线程的线程状态(no start) */NEW,/** *可运行线程的线程状态是可运行的线程状态(not running) *该状态在Java虚拟机中进行,但可能会等待操作系统的其他资源,比如CPU。*有两种内部状态[运行中]和[就绪],可以互相流转。*调用start后,线程处于就绪状态,等待操作系统分配CPU时间片,分配后进入运行状态。*调用yield()方法时,它只是谦恭地允许当前线程放弃CPU,但不是必须这样做。这是由操作系统决定的。如果当前线程被放弃,将进入就绪状态,等待系统分配CPU时间片再次进入运行状态。*/RUNNABLE,/** *阻塞状态。*线程阻塞,等待监视器锁,获得监视器锁后会进入RUNNABLE状态*当发生线程锁争用时,没有获得锁的线程会被挂起,进入阻塞状态,比如synchronized lock。*/BLOCKED,/** *等待线程的线程状态*一个线程在调用以下方法时会处于等待状态:Object.wait()不超时,Thread.join()不超时等。*等待线程正在等待另一个线程执行特定的操作,例如:*一个线程调用了对象上的Object.wait()方法,并正在等待另一个线程调用Object.nofify()或* Object.nofifyAll()方法来打开该对象*一个调用Thread.join()方法的线程正在等待指定的线程终止*/WAITING,/* * *等待线程的线程状态具有指定的等待时间。调用方法时会处于这种状态:Object.wait () timeout,* thread . join()time out thread . sleep(long)等方法。*/TIMED_WAITING,/** *被终止线程的线程状态*线程结束或执行异常终止*/TERMINATED;}
线程生命周期流程图
线程生命周期测试
公共类ThreadStatusDemo { public static void main(String[]args)throws interrupted exception {//Test new runnable terminated thread terminated _ thread=new thread(()-{ long start=system . current time millions();//运行三秒,打印TERMINATED_THREAD while的可运行状态(system。current time millis()-start 3000){ } }, terminated _ thread );//新线程。state state=terminated _ thread . getstate();system . out . println(terminated _ thread . getname() : state= state);terminated _ thread . start();时间单位。seconds . sleep;//可运行线程。state state 1=terminated _ thread . getstate();system . out . println(terminated _ thread . getname() state 1= state 1);TimeUnit.SECONDS.sleep(5); Thread.State state2 = terminated_thread.getState(); // TERMINATED System.out.println(terminated_thread.getName()+"state2 = " + state2); // RUNNABLE new Thread(() -> { while (true) { } }, "Runnle_Thread").start(); // TIMED_WAITING new Thread(() -> { while (true) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "Time_Waiting_Thread").start(); // WAITING new Thread(() -> { while (true) { synchronized (ThreadStatusDemo.class) { try { ThreadStatusDemo.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } }, "Waiting_Thread").start(); // 这两个看谁先抢占到cpu获得锁,另一个就blocked // timed_waiting new Thread(new BlockedDemo(), "Blocke01_Thread").start(); // blocked new Thread(new BlockedDemo(), "Blocke02_Thread").start(); } static class BlockedDemo extends Thread { @Override public void run() { synchronized (BlockedDemo.class) { while (true) { try { TimeUnit.SECONDS.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } }}
启动线程
java中的启动
Java
启动一个线程调用start
方法,start方法内部调用了start0()
native方法。
public synchronized void start() { . . . boolean started = false; try { // 调用native方法 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 */ } }}这个测试是为了验证上图的正确性,只贴了部分.
Hotspot中的启动
查看指引:
在jvm.cpp
找到JVM_StartThread
方法。发现是先创建个JavaThread
作为本地线程然后启动这个本地线程(借助os【thread.cpp】,因为jvm是跨平台的,这里是以linux-os为示例)
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) JVMWrapper("JVM_StartThread"); JavaThread *native_thread = NULL; bool throw_illegal_thread_state = false; { MutexLocker mu(Threads_lock); if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) { throw_illegal_thread_state = true; } else { jlong size = java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread)); size_t sz = size > 0 ? (size_t) size : 0; // 先创建一个JavaThread native_thread = new JavaThread(&thread_entry, sz); if (native_thread->osthread() != NULL) { native_thread->prepare(jthread); } } } if (throw_illegal_thread_state) { THROW(vmSymbols::java_lang_IllegalThreadStateException()); } assert(native_thread != NULL, "Starting null thread?"); if (native_thread->osthread() == NULL) { delete native_thread; if (JvmtiExport::should_post_resource_exhausted()) { JvmtiExport::post_resource_exhausted( JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR JVMTI_RESOURCE_EXHAUSTED_THREADS, "unable to create new native thread"); } THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "unable to create new native thread"); } // 然后启动这个本地线程 thread.cpp Thread::start(native_thread);JVM_ENDJavaThread 创建线程:
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : Thread()#if INCLUDE_ALL_GCS , _satb_mark_queue(&_satb_mark_queue_set), _dirty_card_queue(&_dirty_card_queue_set)#endif // INCLUDE_ALL_GCS{ if (TraceThreadEvents) { tty->print_cr("creating thread %p", this); } initialize(); _jni_attach_state = _not_attaching_via_jni; set_entry_point(entry_point); os::ThreadType thr_type = os::java_thread; thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread : os::java_thread// 调用os(操作系统)创建个线程 os::create_thread(this, thr_type, stack_sz); _safepoint_visible = false; . . .}thread.cpp 启动线程:
// tips: 启动线程的方法void Thread::start(Thread* thread) { trace("start", thread); // Start is different from resume in that its safety is guaranteed by context or // being called from a Java method synchronized on the Thread object. if (!DisableStartThread) { if (thread->is_Java_thread()) { // Initialize the thread state to RUNNABLE before starting this thread. // Can not set it after the thread started because we do not know the // exact thread state at that time. It could be in MONITOR_WAIT or // in SLEEPING or some other state. // tips:启动之后设置线程的状态为 可运行状态 RUNNABLE java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(), java_lang_Thread::RUNNABLE); } // 借助操作系统启动线程 os::start_thread(thread); }}
线程中断与复位
不要使用stop方法
线程的终止不要简单的调用stop
方法,这个方法和其他的线程控制方法(suspend
,resume
)一样都是过期了不建议使用的,这些方法都是不安全的。 例如stop()
方法在结束一个线程的时候并不保证线程资源的正常释放,因此可能导致出现一些不确定的状态。 按照人类逻辑来理解:T1线程调用方法修改T2线程的状态,但是T2现在在做什么T1是不清楚的,所以强制他关闭就是不安全的,就好比在Linux
中使用kill -9
杀掉一个进程。
使用interrupt方法
interrupt()
方法只是修改了被中断线程的中断标志 ,并没有做什么过分的事儿。就像平时写代码的时候修改某对象的标志,对象自己通过标志类决定执行什么逻辑。这里也是一样,interrupt()
方法修改中断标志,被中断的线程,自己决定做什么事儿(中断或者不中断都是被中断线程自己决定的,外部只是通知他,不是强迫他)。追一下源码。 1.Java调用interrupt
方法
2.通过指引找到jvm.cpp#JVM_Interrupt
方法
thread.cpp interrupt 借用操作系统。直接通过系统调用 interruptvoid Thread::interrupt(Thread* thread) { trace("interrupt", thread); debug_only(check_for_dangling_thread_pointer(thread);) // tips: 调用操作系统的interrupt方法 os::interrupt(thread);}这里还是以os_linux.cpp为例最终调用osthread的set_interrupted修改状态
这里就印证了上方的Thread.interrupt()
只是修改了线程的一个标志位 ,并没有做什么过分的事儿。
线程的复位
interrupted
与isInterrupted
这两个放在一起是因为他们底层都是调用的同一个native方法isInterrupted()
只是给了不同的入参。 再就是,有过面试官问到他两的区别,所以干脆放在一起。首先说结论 ,isInterrupted()
会返回线程的中断状态,interrupted()
不仅会返回中断状态,而且如果线程处于状态状态还会将线程终端状态复位(清除中断状态)。
os_linux.cpp的is_interrupted()
方法印证了上面说的isInterrupted()
会返回线程的中断状态,interrupted()
不仅会返回中断状态,而且如果线程处于状态状态还会将线程终端状态复位(清除中断状态)。
其他的线程复位
在Java
中只要抛出了InnterruptException
异常的方法都对线程进行了复位。先理顺下为什么要这么做:查看下基本上抛出InnterruptException
异常的方法都是线程阻塞方法,比如sleep()
,wait()
,join()
。这类方法执行后线程会处于TIMED_WAITING
或者WAITING
状态,处于这类状态的线程是不受控的(线程丧失了对自己的主导,需要其他的线程唤醒,或者阻塞时间到达才能拥有自己的主导权),这个时候线程中断,线程自己却没办法处理。甚至可能永远等不到释放而无法执行中断。所以,在线程是中断状态下,执行方法让线程阻塞,就要抛出一个异常告诉外界 ,我现在是阻塞状态,并且将中断标记复位,方便外界进行处理(例如中断线程的执行或者继续阻塞方法),相当于给了外界一个改变线程状态的入口。 以sleep()
为例追踪下源码:
通过指引找到jcm.cpp#JVM_Sleep
方法入口就直接判断线程的中断状态了 ,is_interrupted()
上面介绍过了,参数为true
就是清除中断标志并且返回清除之前的中断状态。这里线程是中断状态的就直接抛出InnterruptException sleep interrupted
异常了。
到此这篇关于Java线程生命周期的终止与复位的文章就介绍到这了,更多相关Java线程生命周期内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。