1. 程式人生 > >【Java多執行緒程式設計核心技術】第一章 Java多執行緒技能

【Java多執行緒程式設計核心技術】第一章 Java多執行緒技能

執行緒的啟動及常用方法

對於執行緒的啟動來說,首先涉及到的就是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();

缺點:

  1. 如果使用不當,易造成公共的同步物件的獨佔,使得其它執行緒無法訪問公共同步物件(執行緒進入synchronized程式碼塊中被suspend時,不釋放鎖)
  2. 容易導致資料不同步(同步塊中,屬性值修改到一半被suspend,然後有其他執行緒讀取)



如何停止執行緒

停止執行緒:線上程處理完任務之前停掉正在做的操作

停止執行緒的3中方法:

  1. run()完成後執行緒終止
  2. 使用stop()強行終止執行緒,可能產生不可預料的結果,該方法已被廢棄
    • stop()會在run()中的任何地方丟擲ThreadDeath異常來停止執行緒
    • 這種方式,可能導致持有的鎖被突然釋放,導致資料的一致性被破壞
    • 可能使一些請理性的工作得不到完成
  3. 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狀態,就會拋異常,停止執行緒)

  1. 在使用interrupt()之後,檢測中斷狀態,丟擲異常來停止執行緒
  2. 線上程sleep狀態下,呼叫interrupt(),會丟擲異常,並清除停止狀態值,使之變成false
  3. 先呼叫interrupt(),然後再讓執行緒進入sleep狀態,也會丟擲異常
  4. 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);

優先順序特性:

  1. 繼承性:A執行緒啟動B執行緒,則B執行緒的優先順序與A相同
  2. 規則性:優先順序高的大部分先執行完
  3. 隨機性:優先順序高的不一定每次都先執行完



守護執行緒

當程序中不存在非守護執行緒時,守護執行緒自動銷燬(垃圾回收執行緒)

/* 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;
}