進程是處於運行過程當中的程序,而且具備必定的獨立功能java
併發性:同一個時刻只能有一條指令執行,但多個進程指令被快速輪換執行程序員
並行:多條指令在多個處理器上同時執行web
線程是進程的執行單元面試
進程之間不能共享內存,但線程之間很是容易編程
系統建立進程時須要爲該進程從新分配系統資源,但建立線程則代價小得多,所以使用多線程效率更高安全
Java語言內置了多線程功能多線程
public class FirstThread extends Thread { private int i; @Override public void run() { for(i = 0; i < 50; i ++){ System.out.println(this.getName() + "" + i); } } public static void main(String[] args){ FirstThread ft = new FirstThread(); for(int i =0; i < 100;i ++){ System.out.println(Thread.currentThread().getName() + "" + i); if(i == 20) { ft.run(); } } } }
public class FirstThread implements java.lang.Runnable { private int i; public void run() { for(i = 0; i < 50; i ++){ System.out.println(Thread.currentThread().getName()+ "" + i); } } public static void main(String[] args){ FirstThread ft = new FirstThread(); for(int i =0; i < 100;i ++){ System.out.println(Thread.currentThread().getName() + "" + i); if(i == 20) { ft.run(); } } } }
Callable
接口提供了一個call()
方法能夠做爲線程執行體,call()
方法有返回值且能夠聲明拋出異常併發
Java5提供了Future
接口來表明Callable
接口裏call()
方法的返回值,併爲Future
接口提供了一個FutureTask
實現類ide
Future
接口定義的方法:學習
方法名 | 做用 |
---|---|
boolean cancel(boolean mayInterruptIfRunning) |
試圖取消該Future 裏關聯的Callable 任務 |
V get() |
返回Callable 任務裏call 方法的返回值,該方法會形成線程阻塞,等子線程執行完才能得到 |
V get(long timeout, TimeUnit unit) |
返回Callable 任務裏call 方法的返回值。該方法讓程序最多阻塞timeout 和unit 指定的時間,若是通過指定時間Callable 任務尚未返回值則拋出TimeoutException 異常 |
boolean isCancelled() |
Callable 中的任務是否取消 |
boolean isDone() |
Callable 中的任務是否完成 |
public class CallableDemo { public static void main(String[] args){ FutureTask<Integer> task = new FutureTask<Integer>((Callable<Integer>)() -> { int i = 0; for( ; i < 100; i++){ System.out.println(i); } return i; }); new Thread(task).start(); try { System.out.println(task.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
Runnable
和Callable
優劣勢:
線程類只是實現了Runnable
、Callable
接口,還能夠繼承其餘類
Runnable和Callable狀況下,多個線程能夠共享同一個target
對象,因此很是適合多個相同線程來處理同一份資源的狀況
編程稍稍複雜,若是須要訪問當前線程,則必須使用Thread.currentThread()
Thread
優劣勢:
線程類已經繼承了Thread
類,因此不能再繼承其餘父類
編寫簡單,若是須要訪問當前線程,用this
使用
new
語句僅僅由Java虛擬機爲其分配內存,並無表現出任何線程的動態特徵
若是直接調用繼承類的run
方法,則只會有MainActivity
,並且不能經過getName
得到當前執行線程的名字,而需用Thread.currentThread().getName()
調用了run
方法後,該線程已經再也不處於新建狀態
當線程數大於處理器數時,存在多個線程在同一個CPU上輪換的現象
協做式調度策略:只有當一個線程調用了sleep()
或yield()
方法纔會放棄所佔用的資源——即必須線程主動放棄所佔用的資源
搶佔式調度策略:系統給每一個可執行的線程分配一個小的時間段來處理任務,當任務完成後,系統會剝奪該線程所佔用的資源
被阻塞的線程會在合適的時候從新進入就緒狀態
線程狀態轉換圖
測試線程死亡可用isAlive()
處於死亡的線程沒法再次運行,不然引起IllegalThreadStateException
異常
「大清亡於閉關鎖國,學習技術須要交流和資料」。 在這裏我給你們準備了不少的學習資料免費獲取,包括但不限於java進階學習資料、技術乾貨、大廠面試題系列、技術動向、職業生涯等一切有關程序員的分享.java進階方法筆記,學習資料,面試題,電子書籍免費領取,讓你成爲java大神,追到本身的女神,走向人生巔峯
在MainActivity
調用了A.join()
,則MainActivity
被阻塞,A線程執行完後MainActivity
才執行
若是全部的前臺線程都死亡,後臺線程會自動死亡
運行結果
try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); }
sleep
方法暫停當前線程後,會給其餘線程執行機會,不會理會其餘線程優先級;但yield
方法只會給優先級相同或更高的線程
sleep
方法將轉入阻塞狀態,直到通過阻塞時間纔會轉入就緒;yield
強制當前線程轉入就緒狀態
sleep
方法拋出了InterruptedException
,yield方法沒拋出異常
優先級高的線程得到較多的執行機會,優先級低的線程得到較少的執行機會
setPriority
和getPriority
方法來設置和返回指定線程的優先級
run()
方法不具備同步安全性
*java*引入了同步監視器來解決多線程同步問題,sychronized(obj)
中obj
就是共享資源
同步方法就是使用synchronized
來修飾某個方法
實例方法的同步監視器默認是this
*Java*中不可變類老是線程安全的,可變類對象須要額外的方法來保證其線程安全
public class DaemonThread extends Thread { static int balance = 100; int drawAmount; String name; public DaemonThread(int drawAmount, String name){ this.drawAmount = drawAmount; this.name = name; } @Override public void run() { this.draw(drawAmount); } public synchronized void draw(int amount){ if(balance >= amount){ System.out.println(this.name + "取出了" + amount); try{ Thread.sleep(1); } catch (InterruptedException e){ e.printStackTrace(); } balance -= amount; System.out.println("\t餘額爲" + balance); } else{ System.out.println(this.name + "取現失敗"); } } public static void main(String[] args){ new DaemonThread(50, "A").start(); new DaemonThread(100, "B").start(); } }
下列狀況下,線程會釋放對同步監視器的鎖定
當前線程的同步方法、同步代碼塊執行結束
遇到了break、return
程序執行了同步監視器對象的wait()
方法
下列狀況下不會釋放:
執行同步方法時,程序調用Thread.sleep()
Thread.yield()
方法
其餘線程調用了該線程的suspend
方法
*Java5*開始,提供了一種功能更強大的同步鎖機制,能夠經過顯式定義同步鎖對象來實現同步
Lock提供了比synchronized更普遍的鎖定操做,而且支持多個相關的Condition對象
Lock類型: Lock ReadWriteLock ReentrantLock:經常使用,能夠對一個加鎖的對象從新加鎖 ReentrantReadWriteLock StampedLock
方法名 | 做用 |
---|---|
lock |
加鎖 |
unlock |
解鎖 |
A等B,B等A
方法名 | 做用 |
---|---|
wait |
致使當前線程等待,直到其餘線程調用該同步監視器的notify() 或notifyAll() 方法 |
notify |
喚醒在此同步監視器等待的單個線程 |
notifyAll |
喚醒在此同步監視器等待的全部線程 |
wait()
必須在加鎖的狀況下執行
若是系統中不適用synchronized來保證線程同步,而使用Lock對象來保證同步,那麼沒法使用wait
,notify
,notifyAll()
來進行線程通訊
當使用Lock
對象,*Java*提供Condition
保證線程協調
Condition
方法以下
方法名 | 做用 |
---|---|
await |
致使當前線程等待,直到其餘線程調用該同步監視器的signal() 或signalAll() 方法 |
signal |
喚醒在此Lock對象的單個線程 |
signalAll |
喚醒在此Lock對象的全部線程 |
*Java*提供了一個BlockingQueue接口
當生產者線程試圖向BlockingQueue
放入元素時,若是該隊列已滿,則該線程被阻塞;當消費者線程試圖從BlockingQueue
取出元素時,若是該隊列已空,則該線程被阻塞
方法名 | 做用 |
---|---|
put(E e) |
嘗試把E元素放入BlockingQueue |
take() |
嘗試從BlockingQueue 的頭部取出元素 |
public class BlockingQueueThread extends Thread { private BlockingQueue<String> bq; public BlockingQueueThread(BlockingQueue<String> bq){ this.bq = bq; } @Override public void run() { String[] strColl = new String[]{ "Java", "Kotlin", "JavaScript" }; for(int i = 0; i < 1000; i ++){ try { System.out.println(getName() + "開始動工" + i); bq.put(strColl[i % 3]); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName() + "工做結束"); } public static void main(String[] args){ BlockingQueue<String> bq = new ArrayBlockingQueue<>(5); new BlockingQueueThread(bq).start(); } }
結果展現
能夠看到,當Thread-0運行到第6次時就已經被阻塞,不能往裏添加內容
「大清亡於閉關鎖國,學習技術須要交流和資料」。 在這裏我給你們準備了不少的學習資料免費獲取,包括但不限於java進階學習資料、技術乾貨、大廠面試題系列、技術動向、職業生涯等一切有關程序員的分享.java進階方法筆記,學習資料,面試題,電子書籍免費領取,讓你成爲java大神,追到本身的女神,走向人生巔峯
ThreadGroup
表示線程組,能夠對一批線程進行分類管理
子線程和建立它的父線程在同一個線程組內
ThreadGroup
方法
方法名 | 做用 |
---|---|
int activeCount |
返回線程組中活動線程的數目 |
interrupt |
中斷此線程組中全部活動線程的數目 |
isDaemon |
線程組是不是後臺線程組 |
setDaemon |
設置後臺線程 |
setMaxPriority |
設置線程組的最高優先級 |
線程池在系統啓動時即建立大量空閒的線程
程序將一個Runnable
對象或Callable
對象傳給線程池,線程池就會啓動一個空閒線程來執行他們
線程結束不死亡,而是回到空閒狀態
*Java8*以後新增了一個Executors
工廠類來生產線程池
public class ThreadPoolTest { public static void main(String[] args){ ExecutorService pool = Executors.newFixedThreadPool(2); java.lang.Runnable target = () -> { for (int i = 0; i < 100 ; i ++){ System.out.println(Thread.currentThread().getName() + "的i爲" +i); } }; pool.submit(target); pool.submit(target); pool.shutdown(); } }
結果展現
將一個任務拆分紅多個小任務並行計算,再把多個小任務的結果合併成總的計算結果
ForkJoinPool
是ExecutorService
的實現類
public class PrintTask extends RecursiveAction { public static int THREADSH_HOLD = 50; private int start; private int end; public PrintTask(int start, int end){ this.start = start; this.end = end; } @Override protected void compute() { if(end - start < THREADSH_HOLD){ for(int i = start; i < end; i ++){ System.out.println(Thread.currentThread().getName() + "的i爲" + i); } } else { PrintTask left = new PrintTask(start, (start + end) / 2); PrintTask right = new PrintTask((start + end) / 2 , end); left.fork(); right.fork(); } } public static void main(String[] args) throws InterruptedException { PrintTask printTask = new PrintTask(0 , 300); ForkJoinPool pool = new ForkJoinPool(); pool.submit(printTask); pool.awaitTermination(2, TimeUnit.SECONDS); pool.shutdown(); } }