【Java多執行緒程式設計核心技術】第一章 Java多執行緒技能
阿新 • • 發佈:2019-01-07
執行緒的啟動及常用方法
對於執行緒的啟動來說,首先涉及到的就是run()和start()這兩個方法。一種方法是繼承Thread類,覆蓋run方法;一種是實現Runnable介面。
因為開啟執行緒的start方法只在Thread類中存在,所以兩種方法都需要藉助Thread類中的start()來開啟執行緒。
//在Runable介面中只有一個run方法
public interface Runnable {
public abstract void run();
}
//Thread類實現了Runnable
public class Thread implements Runnable {
public synchronized void start() {
//如果多次呼叫start(),會丟擲IllegalThreadStateException異常
if (threadStatus != 0)
throw new IllegalThreadStateException();
//...
}
//由此構造方法可知,還可傳入一個Thread物件,
//將一個Thread物件的run()交給其他執行緒進行呼叫
public Thread(Runnable target) {
//...
}
}
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
* 執行緒還未執行完畢
*/
public final native boolean isAlive();
/**
* Returns a reference to the currently executing thread object.
*/
public static native Thread currentThread();
//sleep方法
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);
}
public static native void sleep(long millis) throws InterruptedException;
//getId()
private long tid;
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
//...
/* Set thread ID */
tid = nextThreadID();
}
/* For generating thread ID */
private static long threadSeqNumber;
private static synchronized long nextThreadID() { return ++threadSeqNumber; }
public long getId() { return tid; }
// A hint to the scheduler that the current thread is willing to yield
// its current use of a processor. The scheduler is free to ignore this
// hint.
public static native void yield();
如何暫停執行緒
@Deprecated
public final void suspend() {
//Determines if the currently running thread has permission to modify this thread.
checkAccess();
suspend0();
}
private native void suspend0();
@Deprecated
public final void resume() {
checkAccess();
resume0();
}
private native void resume0();
缺點:
- 如果使用不當,易造成公共的同步物件的獨佔,使得其它執行緒無法訪問公共同步物件(執行緒進入synchronized程式碼塊中被suspend時,不釋放鎖)
- 容易導致資料不同步(同步塊中,屬性值修改到一半被suspend,然後有其他執行緒讀取)
如何停止執行緒
停止執行緒:線上程處理完任務之前停掉正在做的操作
停止執行緒的3中方法:
- run()完成後執行緒終止
- 使用stop()強行終止執行緒,可能產生不可預料的結果,該方法已被廢棄
- stop()會在run()中的任何地方丟擲ThreadDeath異常來停止執行緒
- 這種方式,可能導致持有的鎖被突然釋放,導致資料的一致性被破壞
- 可能使一些請理性的工作得不到完成
- interrupt()中斷執行緒
- 該方法僅僅是在當前執行緒中打了一個interrupt的標誌
interrupted()與isInterrupted()
//檢測當前執行緒是否是已經中斷狀態,執行後具有將狀態標記清楚為false的功能
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
//測試Thread物件是否已經是中斷狀態,但不清除狀態標誌
public boolean isInterrupted() {
return isInterrupted(false);
}
private native boolean isInterrupted(boolean ClearInterrupted);
能停止執行緒的方法
(interrupt標誌的作用:打上標誌之後,執行緒會繼續執行,一旦執行緒進入sleep狀態,就會拋異常,停止執行緒)
- 在使用interrupt()之後,檢測中斷狀態,丟擲異常來停止執行緒
- 線上程sleep狀態下,呼叫interrupt(),會丟擲異常,並清除停止狀態值,使之變成false
- 先呼叫interrupt(),然後再讓執行緒進入sleep狀態,也會丟擲異常
- interrupt()與return結合也能停止執行緒,通過檢測執行緒中斷狀態
執行緒的優先順序
CPU優先執行優先順序較高的執行緒物件中的任務
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
public final void setPriority(int newPriority) {
ThreadGroup g;
checkAccess();
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
if((g = getThreadGroup()) != null) {
if (newPriority > g.getMaxPriority()) {
newPriority = g.getMaxPriority();
}
setPriority0(priority = newPriority);
}
}
private native void setPriority0(int newPriority);
優先順序特性:
- 繼承性:A執行緒啟動B執行緒,則B執行緒的優先順序與A相同
- 規則性:優先順序高的大部分先執行完
- 隨機性:優先順序高的不一定每次都先執行完
守護執行緒
當程序中不存在非守護執行緒時,守護執行緒自動銷燬(垃圾回收執行緒)
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false;
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}