線程八大核心【一】

1.建立線程的方式

前面我看過不少的博客,部分有說建立線程有多種方式,但JDK1.8源碼Thread中有這麼一段話.ide

There are two ways to create a new thread of execution.One is to declare a class to be a subclass of Thread,The other way to create a thread is to declare a class that implements the Runnable interface.

官方給出的說明是本質上只有兩種方式:1.繼承Thread類,2.實現Runnable接口。但還有不少外在的表現形式,例如lambda表達式,線程池等。this

public class NewThread {
    /*擴展自Thread類*/
    private static class UseThread extends Thread{
        @Override
        public void run() {
            super.run();
            // do my work;
            System.out.println("I am extendec Thread");
        }
    }
    /*實現Runnable接口*/
    private static class UseRunnable implements Runnable{

        @Override
        public void run() {
            // do my work;
            System.out.println("I am implements Runnable");
        }
    }
    
    public static void main(String[] args) 
            throws InterruptedException, ExecutionException {
        UseThread useThread = new UseThread();
        useThread.start();
        UseRunnable useRunnable = new UseRunnable();
        new Thread(useRunnable).start();
    }

2.中止線程的正確姿式

2.1 繼承Thread,執行方法體中沒有InterruptException

直接上代碼:spa

public class EndThread {
    private static class UseThread extends Thread{
        public UseThread(String name) {
            super(name);
        }
        @Override
        public void run() {
            String threadName = Thread.currentThread().getName();
            System.out.println(threadName+" interrrupt flag ="+isInterrupted());
            while(!isInterrupted()){
                //while(!Thread.interrupted()){
                System.out.println(threadName+" is running");
                System.out.println(threadName+"inner interrrupt flag ="
                        +isInterrupted());
            }
            System.out.println(threadName+" interrrupt flag ="+isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread endThread = new UseThread("endThread");
        endThread.start();
        Thread.sleep(20);
        endThread.interrupt();//中斷線程,其實設置線程的標識位true
    }
}

2.1.1 說明:

stop()、suspend()也能中止線程,那麼爲何要將其標註爲Deprecated(過期)的方法呢?緣由就是這種方式是搶佔式的,好比:有一個任務在寫文件,文件的總大小爲10M,如今寫了5M,忽然收到stop()的中斷,致使線程忽然中止,那麼這樣就破壞了文件的完整性。使用interrupt()方法的好處就是,調用該方法時會給線程的中斷標誌位設置爲true,並把中斷線程的決定權交給線程本身,這種方式就是協做式,等任務處理完再結束。

2.1.2 isInterrupt()與Thread.interrupt()靜態方法的區別

相同點:調用interrupt()方法時,二者都能獲取線程的中斷標誌位狀態爲true
不一樣點:Thread.interrupt()在判斷完以後會將中斷標誌位重置爲false

2.2 實現Runnable,執行方法體中沒有InterruptException

public class EndRunnable {
    private static class UseRunnable implements Runnable{
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()
                        + " I am implements Runnable.");
            }
            System.out.println(Thread.currentThread().getName()
                    +" interrupt flag is "+Thread.currentThread().isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        UseRunnable useRunnable = new UseRunnable();
        Thread endThread = new Thread(useRunnable,"endThread");
        endThread.start();
        Thread.sleep(20);
        endThread.interrupt();
    }
}

2.3 執行方法體中有InterruptException

當線程的執行體中出現了sleep、await、join等會拋出interruptException異常的方法時,須要特別注意,就例以下面的程序。線程調用interrupt方法時,線程的執行體會捕獲到interruptException異常,進入到catch中,這時會將線程的中斷標誌位重置爲false。這樣作的意義在於:若是不重置爲false的話,線程收到中斷請求立馬就結束了那麼與stop方法沒有區別了,若是重置爲false,程序能夠在catch中作未完成的工做,如釋放資源等,作完這些收尾的工做以後再手動的調用一次interrupt()方法,結束線程。線程

/**
 *類說明:阻塞方法中拋出InterruptedException異常後,若是須要繼續中斷,須要手動再中斷一次
 */
public class HasInterrputException {
    private static class UseThread extends Thread{
        public UseThread(String name) {
            super(name);
        }
        @Override
        public void run() {
            while(!isInterrupted()) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()
                            +" in InterruptedException interrupt flag is "
                            +isInterrupted());
                    //資源釋放
                    //interrupt();
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                        + " I am extends Thread.");
            }
            System.out.println(Thread.currentThread().getName()
                    +" interrupt flag is "+isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread endThread = new UseThread("HasInterrputEx");
        endThread.start();
        Thread.sleep(500);
        endThread.interrupt();    
    }
}

2.4 錯誤的結束線程方式

設置標誌標誌位,經過判斷標誌位來中斷線程,這種方式的不合理因素在於,若是線程執行體中的方法長時間被阻塞,致使循環阻塞,中斷標誌位失效。code

/**
 *類說明:設置標誌位中斷線程
 */
public class HasInterrputException {
    
    private static class UseThread extends Thread{
        private volatile boolean flag = false;

        public UseThread(String name) {
            super(name);
        }
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
        @Override
        public void run() {
            while(!flag) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()
                            +" in InterruptedException interrupt flag is "
                            +isInterrupted());
                    //資源釋放
                    //interrupt();
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                        + " I am extends Thread.");
            }
            System.out.println(Thread.currentThread().getName()
                    +" interrupt flag is "+isInterrupted());
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread endThread = new UseThread("HasInterrputEx");
        endThread.start();
        Thread.sleep(500);
        ((UseThread) endThread).setFlag(true);
    }
}

3.線程的狀態轉化

jdk源碼對Thread類定義了6個狀態,分別爲:blog

public enum State {
        
        NEW,

        RUNNABLE,
        
        BLOCKED,

        WAITING,

        TIMED_WAITING,

        TERMINATED;
    }

線程的6個狀態.png

4.Thread類的主要方法

相關文章
相關標籤/搜索