《Java多線程編程核心技術(shù)》(一)

概要:
學(xué)習(xí)使用Thread.currentThread()
了解中斷線程的方法
了解sleep方法拋出異常

Thread.currentThread()

Thread.currentThread()方法可返回代碼正在被哪個線程調(diào)用的信息。

public class Counter extends Thread {

    //構(gòu)造方法在主線程中被執(zhí)行
    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() {
        //在子線程中被執(zhí)行
        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();
    }
}

/** 執(zhí)行結(jié)果如下:
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構(gòu)造方法是在main線程中執(zhí)行。run()方法是在new線程中執(zhí)行的。

this.getName()this指代的是Counter實例,Counter繼承Thread,在初始化會設(shè)置名稱為Thread-0。

第二個線程t初始化,名稱默認(rèn)為Thread-1,后續(xù)重新賦值為new。

停止線程

有三種方法可以使終止線程。
1. 使用退出標(biāo)志,使線程正常退出,也就是當(dāng)run方法完成后線程終止。
2. 使用stop方法強行終止線程(這個方法不推薦使用,因為stop和suspend、resume一樣,也可能發(fā)生不可預(yù)料的結(jié)果)。
3. 使用interrupt方法中斷線程。

interrupt()方法僅僅是在當(dāng)前線程中打了一個停止的標(biāo)記,并不是真的停止線程
換句話說,調(diào)用該方法的線程會被設(shè)置一個“中斷”狀態(tài),用于判斷的中斷狀態(tài)的方法如果返回true說明中斷狀態(tài)被設(shè)置了。

如何判斷線程的狀態(tài)是不是停止的?Thread.java類里提供了兩種方法:
1)this.interrupted(): 測試當(dāng)前線程是否已經(jīng)是中斷狀態(tài),執(zhí)行后具有將狀態(tài)標(biāo)志置為false的功能。如果這個方法被連續(xù)調(diào)用兩次,第二次調(diào)用將返回false。
2)this.isInterrupted(): 測試線程Thread對象是否已經(jīng)是中斷狀態(tài),但不清除狀態(tài)標(biāo)識。

第一種方法,判斷當(dāng)前線程的狀態(tài);第二個方法,判斷調(diào)用者的中斷狀態(tài)。

源碼:

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);

從源碼中可以看出,最終調(diào)用的是isInterrupted(boolean ClearInterrupted)方法,參數(shù)ClearInterrupted可以控制中斷狀態(tài)清除。

驗證1:
如下代碼雖然調(diào)用了interrupted()方法,但是從運行結(jié)果來看,線程并未停止。


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。但是并沒有效果。僅僅是打了一個標(biāo)記
        Thread.sleep(10);
        t.interrupt();
    }
}

驗證2:
從運行結(jié)果可以看出,t.interrupted()返回的是當(dāng)前線程的狀態(tài),即main線程,main從未調(diào)用過interrupt()方法,未被標(biāo)記過狀態(tài),因此返回的結(jié)果都是false。

t.isInterrupted()返回的是t線程的中斷狀態(tài)。主線程運行10毫秒之后,調(diào)用中斷方法,此時返回狀態(tài)為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("當(dāng)前線程0:"+t.interrupted());
        System.out.println("停止線程1:"+t.isInterrupted());
        Thread.sleep(1000);
        System.out.println("當(dāng)前線程0:"+t.interrupted());
        System.out.println("停止線程1:"+t.isInterrupted());
    }
}

/**
當(dāng)前線程0:false
停止線程1:true
當(dāng)前線程0:false
停止線程1:false
*/

驗證3
連續(xù)兩次調(diào)用interrupted()方法,第二次調(diào)用將返回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
*/

應(yīng)用
interrupt()方法和isInterrupted()方法結(jié)合使用,來停止線程。

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("已經(jīng)標(biāo)記了停止?fàn)顟B(tài),我要退出");
                break;
            }
            System.out.println("number"+i);
        }
        System.out.println("退出for循環(huán),后面依然執(zhí)行");
}
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
已經(jīng)標(biāo)記了停止?fàn)顟B(tài),我要退出
退出for循環(huán),后面依然執(zhí)行
*/

使用break的方式并未完全退出子線程,for循環(huán)之外的代碼仍然在執(zhí)行

改進(jìn):

2.使用拋異常的方式,停止線程執(zhí)行

public class Counter0 extends Thread {
    @Override
    public void run() {
        try{
            for (int i = 0; i < 100000; i++) {
                if(this.isInterrupted()){
                    System.out.println("已經(jīng)標(biāo)記了停止?fàn)顟B(tài),我要退出");
                    throw new InterruptedException();
                }
                System.out.println("number"+i);
            }

            System.out.println("退出for循環(huán),后面依然執(zhí)行");
        }catch (InterruptedException e){
            System.out.println("捕獲異常");
        }
    }
}
/**
number983
number984
number985
已經(jīng)標(biāo)記了停止?fàn)顟B(tài),我要退出
捕獲異常
*/

在沉睡中停止線程

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當(dāng)前線程睡眠中,如果有任何線程中斷了當(dāng)前線程,拋出異常。當(dāng)拋出異常時,當(dāng)前線程的中斷狀態(tài)被清除,值為false

舉個栗子:

public class Counter0 extends Thread {

    @Override
    public void run() {
        super.run();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            System.out.println("狀態(tài)標(biāo)記:"+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();
        }
    }
}
/**
狀態(tài)標(biāo)記:false
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at com.yolo.thread.Counter0.run(Counter0.java:37)
*/
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容