-
爲什麼要有多線程?
從最開始的真空管穿孔打卡,到後來的晶體管批處理系統,再到後來的集成電路多核並行執行。從硬件資源的級別程度逐漸提高,但是軟件如果對硬件資源利用率低,也是一種資源的損耗,所以隨之而來的進程和線程應運而生。
爲什麼有了進程還需要出現線程?
先說一下進程的弊端。
- 相比進程,對於CPU時間片切換,線程是輕量級的。
- 僅有單線程無線程的話,如果單個IO阻塞了整個進程,那麼程序就會Hang住,從而降低了資源利用率。
而線程是現在cpu執行的最小單位,衆所周知,CPU是通過時間片切換來進行類似於併發的效果的。線程的上下文切換的量級遠小於線程,從而可以更大程度的利用CPU資源。
-
JAVA的線程狀態
其實學習線程狀態最好是看看Thread類源碼,裏面有一個State的Enum類,寫幾個demo看看~現在截圖一下看看Thread源碼關於線程狀態的註釋:
public enum State { /** * Thread state for a thread which has not yet started. */ NEW, /** * Thread state for a runnable thread. A thread in the runnable * state is executing in the Java virtual machine but it may * be waiting for other resources from the operating system * such as processor. */ RUNNABLE, /** * Thread state for a thread blocked waiting for a monitor lock. * A thread in the blocked state is waiting for a monitor lock * to enter a synchronized block/method or * reenter a synchronized block/method after calling * {@link Object#wait() Object.wait}. */ BLOCKED, /** * Thread state for a waiting thread. * A thread is in the waiting state due to calling one of the * following methods: * <ul> * <li>{@link Object#wait() Object.wait} with no timeout</li> * <li>{@link #join() Thread.join} with no timeout</li> * <li>{@link LockSupport#park() LockSupport.park}</li> * </ul> * * <p>A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called <tt>Object.wait()</tt> * on an object is waiting for another thread to call * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on * that object. A thread that has called <tt>Thread.join()</tt> * is waiting for a specified thread to terminate. */ WAITING, /** * Thread state for a waiting thread with a specified waiting time. * A thread is in the timed waiting state due to calling one of * the following methods with a specified positive waiting time: * <ul> * <li>{@link #sleep Thread.sleep}</li> * <li>{@link Object#wait(long) Object.wait} with timeout</li> * <li>{@link #join(long) Thread.join} with timeout</li> * <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li> * <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li> * </ul> */ TIMED_WAITING, /** * Thread state for a terminated thread. * The thread has completed execution. */ TERMINATED; }
一共6種狀態,具體的轉換圖如下:
查看線程狀態可以使用JDK提供的工具來進行輔助~包括JPS,JSTACK。
JPS獲取java進程號。
JSTACK可以獲取線程堆棧的具體信息
-
線程的啓動和銷燬
線程的啓動,不考慮Callable和Future的前提下,只考慮Thread和Runnable。我們看Thread的源碼,我們都是通過調用Start方法而非run方法來啓動線程的。
start方法查看進去,會調用一個start0的native方法。該方法我們就看不到了,因爲是cpp源碼,我們可以找到http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/00cd9dc3c2b5/src/share/native/java/lang/Thread.c 來看具體的Thread的源碼~然後一步一步對應,通過start0-->jvm.cpp裏面的JVM_Start_Thread-->thread.cpp裏面的Thread.Java_thread和Start(需要下載hotspot源碼)-->Thread.start裏面會調用run方法
線程的銷燬
Thread提供了stop和suspend方法,但是都已經過時,其實想想也很正確,A線程調用B線程的stop方法,本身就是一個很奇怪的事情。Thread提供了一個interrupt函數來優雅的中斷一個線程。看源碼又會走到c++源碼中,具體細節不多講了,結果能就是有一個volatile的interrupted的變量變成true,然後呢告知線程,有人向中斷你,僅此而已,至於會不會被中斷,是線程自己的事情。簡單來說就是:
A想中斷B線程,就調用B線程interrupt方法,然後B線程的interrupted boolean變量設置爲true,B線程收到中斷信號,如果不想處理,直接不理這個信號就好,然後調用Thread.interrupted方法來對interrupted變量進行復位。
Thread提供一種IsInterrupted方法來判斷線程是否被中斷。