1、Java多線程基礎

1、簡介

一、操做系統

在早起的裸機時代,計算機很是地昂貴,並且也沒有操做系統的概念,計算機從頭至尾只能執行一個程序。若是程序在執行一個耗時的操做,那麼在這個過程當中,計算機就有大量的資源閒置在那裏,這是很是浪費的。html

而這個時候,操做系統的概念被提出了。在操做系統的控制下,一個計算機能夠執行不少的程序。計算機的資源由操做系統進行分配,程序之間得到計算機資源並執行各自的任務,相互獨立。操做系統的出現使得計算機資源的利用率大大增長。java

你也能夠將操做系統理解爲,運行程序的程序。類比AI是一種產生算法的算法。算法

二、進程和線程

操做系統能夠執行多個程序,每一個程序在計算機中便是一個「進程」。進程的執行是並行的,實際上這裏的「並行」並不徹底是物理意義上的並行。操做系統會給每一個進程分配必定的執行時間,而且CPU在這些進程之間快速地切換執行,從而近似地達到了一種並行執行的效果。固然,現代CPU也從早期的單核發展爲4核、8核,能夠從物理上同時執行。即便是單核,也可以控制多個執行流達到物理上併發的目的。編程

操做系統使得程序得以併發執行,但隨着需求的增長,咱們但願每一個程序也可以併發多個任務。因此,線程的概念就應運而生了。線程是依賴於進程的,共享進程的計算機資源。一個進程能夠擁有一到多個線程。線程的並行執行和進程的理念是同樣的,共享進程的時間片,快速地執行切換。api

三、Java多線程

Java編程語言爲幫助開發者開發多線程的應用程序設計了一套簡單的語義,你能夠利用Java的內置支持來構建多線程程序,充分利用CPU資源,提升程序的響應速度多線程

2、Java線程的生命週期

下圖,摘錄自菜鳥教程:http://www.runoob.com/java/java-multithreading.html併發

這個圖相信你們都很熟悉,它是表達了線程的生命週期,包含了幾個狀態,以下:異步

1)建立:當咱們在程序中new出來一個線程實例對象的時候,線程便處於建立狀態;編程語言

2)就緒:當咱們調用了start()方法,表示該線程即將等待JVM的native方法去調用咱們的線程,也就是就緒狀態;ide

3)運行:若是JVM調用了咱們的線程,線程實例執行中,它就處於運行狀態;

4)阻塞:運行過程當中可能出現sleep、wait或者其它IO操做等,這個時候當前的線程就處於阻塞狀態,讓出CPU的資源,而不是繼續佔用。

5)死亡:若是線程正常執行完畢,手動退出或者意外結束,那麼線程就進入了死亡狀態,該線程佔用的資源也會被自動回收。

3、使用示例

Java顯示建立線程有兩種實現:

1)繼承Thread類

public class ThreadDemo extends Thread { @Override public void run() { System.out.println("執行了" + Thread.currentThread().getName()); } public static void main(String[] args) { new ThreadDemo().start(); System.out.println("主線程執行了" + Thread.currentThread().getName()); } }

事實上,Thread類實現了Runnable接口,而咱們重寫了Runnable的run方法,當調用start()方法的時候,該線程會調用native方法,從而JVM會去異步執行線程實例的run方法。

2)實現了Runnable接口

public class RunnableDemo implements Runnable { @Override public void run() { System.out.println("線程執行" + Thread.currentThread().getName()); } public static void main(String[] args) { new Thread(new RunnableDemo()).start(); System.out.println("主線程執行" + Thread.currentThread().getName()); } }

實現Runnable接口的方式,也須要將Runnable做爲Thread實例的構造入參,而後經過start()將線程轉換爲就緒狀態。若是你直接調用run方法是不會異步運行的。

以上兩種實現,其實都是基於Runnable接口和Thread類,只是寫法不一樣。

4、經常使用API

  1. currentThread():靜態方法,返回當前線程的引用
  2. getId():返回當前線程的標識符
  3. getName():返回當前線程的引用
  4. getPriority():返回當前線程的優先級
  5. getState():返回當前線程的狀態
  6. interrupt():中斷線程(僅是打上中斷標識,沒法強制中止線程)
  7. interrupted():靜態方法,返回是否中斷
  8. isAlive():是否存活
  9. isDaemon():是否守護線程
  10. isInterrupted():是否中斷
  11. yield():靜態方法,暫停當前線程,執行其它線程
  12. start():使線程進入就緒狀態
  13. sleep(long millis):靜態方法,使線程休眠
  14. setPriority(int priority):設置優先級,優先級高的會先執行
  15. setName():設置名字
  16. setDaemon():設置爲守護線程
  17. join():等待其它線程停止之後再繼續執行
  18. wait():等待notify喚醒
  19. notify():喚醒wait線程

yield示例

yield執行的時候暫停當前線程執行,讓出CPU資源,去執行其它線程

public class YieldDemo { private static volatile boolean isReady = false; public static void main(String[] args) throws InterruptedException { new Thread(() -> { System.out.println(Thread.currentThread().getName() + "讓主線程執行"); while (!isReady) { Thread.yield(); } System.out.println(Thread.currentThread().getName() + "執行完畢"); }).start(); Thread.sleep(5000); isReady = true; System.out.println(Thread.currentThread().getName() + "執行完畢"); } }

join示例

join的做用是讓將某個線程插入到當前線程的執行位置,並等待該線程執行完畢之後再執行當前線程。

public class JoinDemo { public static void main(String[] args) throws InterruptedException { Thread thread = new Thread(() -> { System.out.println(Thread.currentThread().getName() + "開始執行"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "執行完畢"); }); thread.start(); System.out.println(Thread.currentThread().getName() + "等待子線程執行完畢"); thread.join(); System.out.println(Thread.currentThread().getName() + "執行完畢"); } }

notify/wait示例

notify和wait使用比較特殊,須要得到同步鎖資源

notify和wait方法是Object對象的方法,任何對象都會有。它的做用是什麼呢?咱們舉一個場景示例:

1)存在兩個線程A和B;

2)咱們但願A執行完畢之後通知B去執行,而B在A通知以前一直等待

代碼示例以下:

public class WaitDemo { private static Object lock = new Object(); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 3; i++) { new Thread(() -> { // 要先得到同步鎖
                synchronized (lock) { try { System.out.println(Thread.currentThread().getName() + " waiting"); // 等待notify
 lock.wait(); System.out.println(Thread.currentThread().getName() + " end waiting"); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } System.out.println("sleep"); Thread.sleep(5000); // 要先得到同步鎖
        synchronized (lock) { System.out.println("notify"); // 執行notify
 lock.notifyAll(); System.out.println("finished"); } } }

這裏隨意創建了一個lock對象做爲鎖對象,子線程拿到這個鎖之後執行等待。而主線程拿到鎖之後,發送通知,執行結果以下:

sleep Thread-0 waiting Thread-1 waiting Thread-2 waiting notify finished Thread-2 end waiting Thread-1 end waiting Thread-0 end waiting

注意:若是notifyAll()在wait()以前執行了,那麼子線程將無線等待下去,你能夠給wait設置超時時間

更多API示例,參考JDK文檔:http://tool.oschina.net/uploads/apidocs/jdk-zh/java/lang/Thread.html

相關文章
相關標籤/搜索