線程驅動任務,而咱們須要的就是一種任務的描述,而這個描述由Runable接口來提供,想定義任務,只須要實現Runable接口並重寫裏面的run()就好
java
方法名 | 描述 |
---|---|
Thread() | 建立新線程對象 |
Thread(String name) | 建立新線程對象 |
Thread(Runnable target) | 建立新線程對象 |
Thread(Runnable target, String name) | 建立新線程對象,name爲指定的線程名 |
Thread(ThreadGroup group, Runnable target) | 分配新的 Thread 對象。 |
Thread(Runnable target) | 建立新線程對象 |
Thread構造器一般須要一個Runable對象,咱們把須要執行的任務放在run()中,程序運行後,會自動執行Runable對象的run()方法,以便在新的線程中執行咱們指定的任務. start()方法是告訴cpu線程處於就緒狀態算法
public class demo01 extends Thread { public demo01(String name){ super.setName(name); } public demo01(){ } @Override public void run() { while(true) System.out.println(Thread.currentThread().getName()+"繼承Thread類的線程執行了..."); } public static void main(String[] args) { //new demo01() 執行Thread空參構造方法... demo01 d = new demo01(); demo01 d2 =new demo01("helloThread"); //線程就緒 d.start(); d2.start(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } }
實現runable接口 其實demo02 本類並非一個Thread 他是一個線程任務編程
public class demo02 implements Runnable{ @Override public void run() { // while(true) System.out.println(Thread.currentThread().getName()+"線程執行了..."); } public static void main(String[] args) { demo02 d = new demo02(); Thread myThread = new Thread(d); myThread.start(); //lamaban表達式實現的run方法 new Thread(()->{ while(true) System.out.println("lamaban表達式實現的run方法執行了..."); } ).start(); //直接寫 new Thread(){ @Override public void run() { System.out.println("hello Thread.."); } }.start(); //實現Runable() + 繼承Thread(); new Thread(new Runnable() { @Override public void run() { System.out.println("Runnable接口裏面的run"); } }){ //子類覆蓋了 父類的run方法... @Override public void run(){ System.out.println("Thread子類裏面的run"); } }.start(); } }
通常狀況下,若是不是多繼承,實現Runable接口和繼承Thread類沒啥區別api
Callable一樣能夠理解成是一個任務的描述方式,只不過他不能直接丟給Thread,而是交給一個叫FutrueTask的容器包裝,多線程
Callable更強大一些.運行Callable的任務,能夠拿到一個Future的對象,咱們能夠先經過這個對象isDone()判斷任務是否結束,而後調用get()獲取運行的返回值異步
一來講多個線程之間是異步執行的,咱們很難從一條線程拿到另外一條線程的返回值,這個時候Futrue就出場了,對於Callable和Runable提交過來的任務,他能夠進行查詢任務是否完成 isDone() 獲取執行結果get() 取消任務cancel()ide
此外咱們能夠知道它最終也是執行Callable類型的接口,若是傳遞進來的是Runable的實現,那麼它會先把他轉化成Callable,函數
public class demo03 implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("hello Callable"); //返回值的類型就是Callable接口的泛型 return 1; } public static void main(String[] args) throws ExecutionException, InterruptedException { //將來的任務 FutureTask<Integer> task = new FutureTask<>(new demo03()); new Thread(task).start(); System.out.println("返回值的結果是:"+task.get()); } }
剛纔提到,Thread接收的任務是Runable類型的,如今FutureTask是個什麼鬼?怎麼把它傳遞進來的? 其實,FutrueTask實現了RunnableFuture接口,而這個接口繼承了Runnable&Future,一切也就那麼順其天然了this
固然咱們知道,Runable裏面的run()方法是由新new出來的線程異步執行的,那麼如今重寫的這個call()怎麼個運行法?操作系統
查看FutrueTask的源碼,咱們能夠看到,call()是由FetureTask的run()執行的,
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true;
run()方法&call()方法
Runable的Run方法 是由 線程異步調用的
雖然是耗時的操做,若是可能出現阻塞,由新的線程中執行,會節省時間
Callable的 call 方法,同步調用的,是由Future的run方法調用的,而這個run方法,是對Runable接口裏面run()的重寫
依然是耗時的操做
在往線程池中提交任務時 submit()方法一樣可接受Callable對象,後續會詳解
Future<String> future = threadPoolExecutor.submit(new Callable<String>() { @Override public String call(){ ai.getAndIncrement(); return Thread.currentThread().getName(); } });
interrupted():
它要配合 isInterrupted() ,做爲條件,判斷當前的狀態,去中斷, 本函數屢次調用不會 改變 當前線程的狀態
實例代碼
/* * 中止不了的線程 * */ public class CanNotStop extends Thread{ AtomicInteger value = new AtomicInteger(1); @Override public void run() { value.getAndIncrement(); System.out.println("當前的value== "+value); /* * isInterrupted() 方法, 判斷當前線程的狀態去中斷線程, * 假如說,當前線程被標記爲要去中斷, 被isInterrupted()限制的Target方法再也不執行,條件以外的代碼,能且只能執行一次! 而後完全被中斷 * */ while(!isInterrupted()) { try { sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } try { sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "執行了.."); } System.out.println("你真的覺得我被中斷了嗎?"); } public static void main(String[] args) { //初始化 CanNotStop canNotStop = new CanNotStop(); CanNotStop canNotStop2 = new CanNotStop(); canNotStop.start(); canNotStop2.start(); /* * 關於interrupt()方法,這個方法 * 做用: * 中斷當前線程,可是! 相比於廢棄的stop() 並非真正意義上的中斷,而是打上了一個標記, 表示想要中斷它.可是呢?在中斷它以前要讓他把該作的事, * 該跑的代碼 跑完! * 特性: * 第一次執行interrupt()----> 標記當前線程是要被中斷的 * 第二次執行interrupt()----> 清除全部標記 * * 它要配合 isInterrupted() ,做爲條件,判斷當前的狀態,去中斷, 本函數屢次調用不會 改變 當前線程的狀態 * */ canNotStop.interrupt(); try { sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } //被中斷就至關於死掉了? synchronized (canNotStop){ canNotStop.notifyAll(); } } }
這也稱做是中止不了的線程,爲啥這樣說呢? 能夠看到,執行 canNotStop.interrupt();代碼的是誰? 沒錯主線程!細想一下,執行這個語句時,新建立的線程,原本就沒有搶到CPU的執行權,也就是說他原本就是中止的... 他的原理就是打個標記,等到被打上標記的線程搶到CPU的執行權的時候,去判斷一下就好了,若是存在被中斷的標記,就什麼事都不作,反之則執行任務.其實,它還活着
返回當前代碼,正在被哪一個線程調用
判斷當前線程是否處於存活狀態,線程處於正在運行或者等待運行的狀態返回true,線程運行完畢返回false
指定在線程休眠的時間,在指定的時間後,從新進入就緒狀態去競爭CPU的執行權
返回線程的id & 名字
throw new InterruptedException();
@Override public void run(){ while(true){ if(this.isInterrupted()){ return; } System.out.println("if 後面的代碼"); } }
推薦使用的是剖出異常的中止線程的方法,由於有了異常以後,能夠在catch塊中對異常進行處理,讓程序更加流暢
線程的優先級用處是,把任務的重要性告訴調度器,讓任務的調度器,更傾向於優先級高的線程先執行,可是也存在優先級底的線程先執行的可能
在<
>提到,在絕大多數狀況下,都應該使線程按照默認的優先級規則執行,試圖操做優先級讓線程先執行,一般是一種錯誤
此外,jdk中線程的優先級有是個,可是和操做系統都不能映射的很好,好比Windows系統是七個優先級,因此通常咱們使用的是 MAX_PRIORITY NORM_PRIORITY MIN_PRIORITY
setPriority(int newPriority);
其中newPriority的值由1-10 ,若不在這個範圍內,拋出IllegalArgumentExeception()
getPriority();
特性:
設置爲守護線程, 它確定會隨着主線程的退而退出
java線程中有兩類,一類是用戶線程(非守護線程) 一類是守護線程. 它的特性就是 伴隨,去守護用戶線程,
好比 java的GC(垃圾回收算法) 就是一個很稱職的守護者!
setDaemon(true);
public class demo02 implements ThreadFactory { @Override public Thread newThread(Runnable r) { Thread thread = newThread(r); thread.setDaemon(true); return thread; } }
ExecutorService executorService = Executors.newCachedThreadPool(new demo02());
當再沒有非守護線程後,守護線程中run方法中的finally代碼塊是不會執行而直接退出
參考書籍<