1. 程式人生 > >《Java多執行緒程式設計核心技術》(一)

《Java多執行緒程式設計核心技術》(一)

概要:
學習使用Thread.currentThread()
瞭解中斷執行緒的方法
瞭解sleep方法丟擲異常

Thread.currentThread()

Thread.currentThread()方法可返回程式碼正在被哪個執行緒呼叫的資訊。

public class Counter extends Thread {

    //構造方法在主執行緒中被執行
    public Counter() {
        print("constructor begin");

        print("Thread.currentThread().getName()------"
+Thread.currentThread().getName());//main print("this.getName()-----------"+this.getName());//Thread-0 print("constructor end"); } @Override public void run() { //在子執行緒中被執行 print("run begin"); print("Thread.currentThread().getName()--------"+Thread.currentThread().getName()); print("this.getName()--------"
+this.getName()); print("run end"); } private void print(String msg){ System.out.println(msg); } } public class Run { public static void main(String[] args){ Counter counter = new Counter(); Thread t = new Thread(counter); t.setName("new"
); t.start(); } } /** 執行結果如下: constructor begin Thread.currentThread().getName()------main this.getName()-----------Thread-0 constructor end run begin Thread.currentThread().getName()--------new this.getName()--------Thread-0 run end */

如上,Counter構造方法是在main執行緒中執行。run()方法是在new執行緒中執行的。

this.getName()this指代的是Counter例項,Counter繼承Thread,在初始化會設定名稱為Thread-0

第二個執行緒t初始化,名稱預設為Thread-1,後續重新賦值為new

停止執行緒

有三種方法可以使終止執行緒。
1. 使用退出標誌,使執行緒正常退出,也就是當run方法完成後執行緒終止。
2. 使用stop方法強行終止執行緒(這個方法不推薦使用,因為stop和suspend、resume一樣,也可能發生不可預料的結果)。
3. 使用interrupt方法中斷執行緒。

interrupt()方法僅僅是在當前執行緒中打了一個停止的標記,並不是真的停止執行緒
換句話說,呼叫該方法的執行緒會被設定一個“中斷”狀態,用於判斷的中斷狀態的方法如果返回true說明中斷狀態被設定了。

如何判斷執行緒的狀態是不是停止的?Thread.java類裡提供了兩種方法:
1)this.interrupted(): 測試當前執行緒是否已經是中斷狀態,執行後具有將狀態標誌置為false的功能。如果這個方法被連續呼叫兩次,第二次呼叫將返回false。
2)this.isInterrupted(): 測試執行緒Thread物件是否已經是中斷狀態,但不清除狀態標識。

第一種方法,判斷當前執行緒的狀態;第二個方法,判斷呼叫者的中斷狀態。

原始碼:

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

public boolean isInterrupted() {
    return isInterrupted(false);
}

/**
 * Tests if some Thread has been interrupted.  The interrupted state
 * is reset or not based on the value of ClearInterrupted that is
 * passed.
 */
private native boolean isInterrupted(boolean ClearInterrupted);

從原始碼中可以看出,最終呼叫的是isInterrupted(boolean ClearInterrupted)方法,引數ClearInterrupted可以控制中斷狀態清除。

驗證1:
如下程式碼雖然呼叫了interrupted()方法,但是從執行結果來看,執行緒並未停止。


class MyThread extends Thread{
    @Override
    public void run() {
        for(int i =0;i<1000;i++){
            System.out.println("number"+i);
        }
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread t = new MyThread();
        t.start();
        //主執行緒執行10毫秒之後,中斷子執行緒t。但是並沒有效果。僅僅是打了一個標記
        Thread.sleep(10);
        t.interrupt();
    }
}

驗證2:
從執行結果可以看出,t.interrupted()返回的是當前執行緒的狀態,即main執行緒,main從未呼叫過interrupt()方法,未被標記過狀態,因此返回的結果都是false

t.isInterrupted()返回的是t執行緒的中斷狀態。主執行緒執行10毫秒之後,呼叫中斷方法,此時返回狀態為true,表示t.interrupt()方法生效了。

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread t = new MyThread();
        t.start();  
        //主執行緒執行10毫秒之後,中斷子執行緒t。     
        Thread.sleep(10);
        t.interrupt();
        System.out.println("當前執行緒0:"+t.interrupted());
        System.out.println("停止執行緒1:"+t.isInterrupted());
        Thread.sleep(1000);
        System.out.println("當前執行緒0:"+t.interrupted());
        System.out.println("停止執行緒1:"+t.isInterrupted());
    }
}

/**
當前執行緒0:false
停止執行緒1:true
當前執行緒0:false
停止執行緒1:false
*/

驗證3
連續兩次呼叫interrupted()方法,第二次呼叫將返回false

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().interrupt();
        System.out.println("停止執行緒:"+Thread.currentThread().interrupted());
        System.out.println("停止執行緒:"+Thread.currentThread().interrupted());
    }
}
/**
停止執行緒:true
停止執行緒:false
*/

應用
interrupt()方法和isInterrupted()方法結合使用,來停止執行緒。

1.使用break停止執行緒

public class Counter0 extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 100000; i++) {
            if(this.isInterrupted()){
                System.out.println("已經標記了停止狀態,我要退出");
                break;
            }
            System.out.println("number"+i);
        }
        System.out.println("退出for迴圈,後面依然執行");
}
public class Run {

    public static void main(String[] args){
        try {
            Counter0 counter0 = new Counter0();
            counter0.start();
            Thread.sleep(10);
            counter0.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
number776
number777
number778
number779
number780
已經標記了停止狀態,我要退出
退出for迴圈,後面依然執行
*/

使用break的方式並未完全退出子執行緒,for迴圈之外的程式碼仍然在執行

改進:

2.使用拋異常的方式,停止執行緒執行

public class Counter0 extends Thread {
    @Override
    public void run() {
        try{
            for (int i = 0; i < 100000; i++) {
                if(this.isInterrupted()){
                    System.out.println("已經標記了停止狀態,我要退出");
                    throw new InterruptedException();
                }
                System.out.println("number"+i);
            }

            System.out.println("退出for迴圈,後面依然執行");
        }catch (InterruptedException e){
            System.out.println("捕獲異常");
        }
    }
}
/**
number983
number984
number985
已經標記了停止狀態,我要退出
捕獲異常
*/

在沉睡中停止執行緒

public class Thread implements Runnable{
    /**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     *
     * @param  millis
     *         the length of time to sleep 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 static native void sleep(long millis) throws InterruptedException;
}

InterruptedException當前執行緒睡眠中,如果有任何執行緒中斷了當前執行緒,丟擲異常。當丟擲異常時,當前執行緒的中斷狀態被清除,值為false

舉個栗子:

public class Counter0 extends Thread {

    @Override
    public void run() {
        super.run();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("狀態標記:"+this.isInterrupted());
            e.printStackTrace();
        }
    }
}
public class Run {
    public static void main(String[] args){
        try {
            Counter0 counter0 = new Counter0();
            counter0.start();
            Thread.sleep(10);
            counter0.interrupt();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
/**
狀態標記:false
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.yolo.thread.Counter0.run(Counter0.java:37)
*/