本人郵箱: <kco1989@qq.com>
歡迎轉載,轉載請註明網址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代碼已經所有託管github有須要的同窗自行下載java
學習java線程的開發者,首先遇到的第一個類就是Thread,經過使用Thread類,咱們就能夠啓動,中止,中斷一個線程. 在同一個時間片裏, 可能會有多個線程在執行, 每一個線程都擁有它本身的方法調用堆棧, 參數和變量.每一個app至少會有一個線程--主線程(main thread).git
建立一個繼承Thread
的子類,並實現run
方法github
使用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(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
執行完以後纔開始執行
這個方法標識當前線程會按時線程調度者讓其餘線程先執行.但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"); } }
若是以爲個人文章寫的還過得去的話,有錢就捧個錢場,沒錢給我捧我的場(幫我點贊或推薦一下)