(一)java多線程之Thread

本人郵箱: <kco1989@qq.com>
歡迎轉載,轉載請註明網址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經所有託管github有須要的同窗自行下載java

Thread類

學習java線程的開發者,首先遇到的第一個類就是Thread,經過使用Thread類,咱們就能夠啓動,中止,中斷一個線程. 在同一個時間片裏, 可能會有多個線程在執行, 每一個線程都擁有它本身的方法調用堆棧, 參數和變量.每一個app至少會有一個線程--主線程(main thread).git

建立一個線程

java建立線程有兩種方式

  1. 建立一個繼承Thread的子類,並實現run方法github

  2. 使用Thread的構造方法public Thread(Runnable target)建立,這個須要傳入一個實現Runnable接口的子類微信

實現

下面咱們分別以這兩種方式實現一下.app

  • 編寫SubThread繼承Thread,並覆蓋run方法 SubThread.javaide

public class SubThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i ++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }

    public static void main(String[] args) {
        System.out.println("begin main");
        SubThread sub = new SubThread();
        sub.start();
        System.out.println("end main");
    }
}
  • 編寫SubRunnable實現Runnable,而後使用構造器Thread(Runnable) 建立一個線程學習

public class SubRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i ++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
    public static void main(String[] args) {
        System.out.println("begin main");
        Thread thread = new Thread(new SubRunnable());
        thread.start();
        System.out.println("end main");
    }
}

區別

  • 使用第一種方法建立的話,你能夠在run方法中,能夠用this直接調用線程的方法,好比獲取線程的id-->this.getId()this

  • 而使用第二方法建立線程,在run中,this對象壓根就沒有getId()這個方法,這個時候你只能用Thread.cuurentThread()這個靜態方法獲取該線程.spa

  • 在這裏通常推薦使用第二種方法建立,由於這樣比較符合面對象的思路,Thread就只負責線程的啓動,中止,中斷等操做,而Runnable就只負責線程要運行某一個具體任務..net

無論使用那種方式建立線程,均可以調用Thread.cuurentThread()獲取當前的線程
還有,Thread其實也是Runnable的一個子類
除了上面兩種建立方法,其中還有另一種方法建立線程,那就是實現ThreadFactory接口,這種比較適合批量生成某一種規格的線程

讓線程"睡"一會

調用線程的Thread.sleep()方法會讓線程睡眠一段時間,這個時候線程會掛起,而後將CPU的時間片轉移給其餘線程,讓其餘線程得到執行的機會.

Thread.sleep()接收一個毫秒值作完參數,並拋出一個InterruptedException異常.

中止線程

不論是使用哪種方法建立線程,run方法的任務執行完了,線程就自動中止.
若是想在中途就中止線程,有下面幾種方式

  • 調用線程的interrupt()方法,這時線程的中斷位會被標識,並拋出InterruptedException,例如:

public class StopThread1 {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("begin main");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {

                for (int i = 0; i < 10; i ++){
                    try {
                        Thread.sleep(100);
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    } catch (InterruptedException e) {
                        break;
                    }
                }
            }
        });
        thread.start();
        System.out.println("main sleep 500ms");
        Thread.sleep(500);
        thread.interrupt();
        System.out.println("end main");
    }
}

在調用thread.interrupt();這個語句時,會對該線程的中斷狀態標識爲true,而後在拋出InterruptedException異常時,會清空該中斷位.
修改程序,在拋出InterruptedException中添加System.out.println("InterruptedException:" + Thread.currentThread().isInterrupted());,而後再thread.interrupt();後面添加System.out.println("thread.isInterrupted:" + thread.isInterrupted());.而後運行程序.

這時候運行結果有可能打印出thread.isInterrupted:true;InterruptedException:false或者打印出thread.isInterrupted:false;InterruptedException:false,運行屢次結果都有可能不一致,這個是由於主線程和子線程都通知在執行,尚未來的及執行主線程的打印語句,子線程異常中的打印語句就已經執行了.

  • 能夠在線程中加一個boolean成員變量,提供setter方法,而後在run方法中判斷該變量是否爲true,若爲true則中止線程,不然繼續

public class StopThread2 {
    public static class StopRunnable implements Runnable{
        private boolean isStop = false;

        public void setStop(){
            this.isStop = true;
        }
        @Override
        public void run() {
            int count = 0;
            while (!isStop){
                try {
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + ":" + count++);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println("begin main");
        StopRunnable stop = new StopRunnable();
        Thread thread = new Thread(stop);
        thread.start();
        Thread.sleep(200);
        stop.setStop();
        System.out.println("end main");
    }
}

線程的屬性

  • id: 經過Thread.getId()能夠獲取線程的id,線程的id是一個自增加的long, 不能修改

  • name: 經過Thread.getName(), 用一個字符串來標識線程的名字,能夠經過Thread.setName()或部分構造器修改線程的名字

  • priority: 線程的優先級,線程建立默認優先級爲5, 最小爲優先級爲1, 最大爲10.優先級大的線程有機會先執行.但具體那個線程先執行仍是要看CPU的心情了.

  • state: 線程的狀態, 線程的狀態有如下幾種

    • Thread.State.NEW: _新建狀態_:這個是線程已經被建立但尚未調用'start()'方法時的狀態

    • Thread.State.RUNNABLE: 運行狀態 當前線程已經在JVM中執行

    • Thread.State.BLOCKED: 阻塞狀態 表示當前線程在等待進入一個同步塊或同步方法,也能夠等到一個同步快被提交. 常見的有IO阻塞等.

    • Thread.State.WAITING: 等待狀態 但線程調用Object.wait(),Thread.join(),LockSupport.park()就會進入等待狀態.當前線程在等待其餘線程執行某一個特定操做.好比:當前線程執行Object.wait(),那麼就須要其餘線程執行Object.notify()Object.notifyAll(),若是線程執行了Thread.join(),則須要等到指定的線程執行結束.

    • Thread.State.TIMED_WAITING: 有時間的等待 線程在等待某一個等待的時間.好比,線程執行了Thread.sleep,Object.wait(long),Thread.join(long)

    • Thread.State.TERMINATED: 終結 線程已經執行完畢.

  • daemon: 這個用來標識線程爲守護線程或非守護線程的,默認建立的線程都是非守護線程.應用程序全部的非守護線程執行完畢以後,則程序就中止運行.好比主線程都是非守護線程,因此主線程會等到主線程的全部語句執行完成,程序纔會中止運行.JVM的資源回收則是一個守護線程.

public class TestDaemonThread {
    public static void main(String[] args) {
        System.out.println("start main");
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i ++){
                    try {
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                        Thread.sleep(10);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        thread.start();
        System.out.println("end main");
    }
}

該例子中,程序必須等到主線程和子線程同時執行完成纔會中止,由於默認建立的線程都是非守護線程,若是在thread.start();前加入thread.setDaemon(true);, 那麼程序不會等子線程執行完才結束程序的.

Thread.join()

等到某線程執行完畢纔開始執行,若是調用Thread.join(long)則表示等到某線程執行完畢或指定的超時時間結束後纔開始執行

public class ThreadJoinTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            for (int i = 0;i < 10; i ++){
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "thread1");
        Thread thread2 = new Thread(() -> {
            try {
                thread1.join();
                for (int i = 0;i < 10; i ++){
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + ":" + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "thread2");
        thread1.start();
        thread2.start();

    }
}

上面的例子,thread2線程會等thread1執行完以後纔開始執行

Thread.yield

這個方法標識當前線程會按時線程調度者讓其餘線程先執行.但CPU是否讓其餘線程優先執行,仍是要看CPU的心情了.

線程的異常

若是線程發現一些運行時異常而沒有在run方法俘獲,會怎麼辦?

程序會打印出一推錯誤堆棧,若是咱們先把線程的錯誤按照某種可讀的方式打印到問題,但又不想在每一個run方法中增長try{...}catch(Exception e){...}怎麼辦?

咱們查看Thread類的源碼發現,在Thread中有一個內部接口UncaughtExceptionHandler,這個正是咱們所須要的.實現這個接口,並調用Thread.setUncaughtExceptionHandler,那麼但線程出現時,則會回調uncaughtException方法

public class ThreadExceptionTest {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("begin main");
        Thread thread = new Thread(() -> {
            int i = 1 / 0;
        },"myThread");
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println(String.format("%s發生異常%s", t.getName(), e.getMessage()));
            }
        });
        thread.start();
        System.out.println("end main");
    }
}

打賞

若是以爲個人文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧我的場(幫我點贊或推薦一下)
微信打賞
支付寶打賞

相關文章
相關標籤/搜索