進程是程序的一次執行過程,是系統運行程序的基本單位,所以進程是動態的。系統運行一個程序便是一個進程從建立、運行到消亡的過程。java
線程是比進程更小的執行單位,一個進程在其執行的過程當中能夠產生多個線程。線程共享進程的堆和方法區的資源,同時線程還有私有的程序計數器、虛擬機棧和本地方法棧資源。安全
並行:單位時間內,多個任務同時執行。多線程
併發:同一時間段,多個任務都在執行(單位時間內不必定同時執行)。併發
狀態名稱 | 說明 |
---|---|
NEW | 初始狀態,線程被構建 |
RUNNABLE | 運行狀態,包括運行中和就緒兩種狀態 |
BLOCKED | 阻塞狀態,表示線程阻塞於鎖 |
WAITING | 等待狀態,表示線程進入等待狀態,若是其餘線程不通知則不會喚醒 |
TIMED_WAITING | 超時等待狀態,通過指定等待時間後會自動喚醒 |
TERMINATED | 終止狀態,表示線程已經執行完畢 |
經過繼承Thread類並重寫run() 方法能夠建立線程,調用start()方法來啓動線程。ide
public class ThreadDemo01 { public static void main(String[] args) { MyThread01 t = new MyThread01(); t.start(); // 線程名稱:Thread-0 } } /** * 繼承Thread類 */ class MyThread01 extends Thread { @Override public void run() { System.out.println("線程名稱:" + Thread.currentThread().getName()); } }
因爲Java中類的單繼承特性,當一個類繼承Thread類後就不能繼承其它的類了。線程
經過實現Runnable接口並重寫run() 方法能夠建立一個線程,同時能夠繼承其它的類。code
public class ThreadDemo02 { public static void main(String[] args) { new Thread(new MyThread02()).start(); // 線程名稱:Thread-0 } } /** * 實現Runnable接口 */ class MyThread02 extends Object implements Runnable { @Override public void run() { System.out.println("線程名稱:" + Thread.currentThread().getName()); } }
採用這種方式建立線程時能夠利用JDK1.8的新特性lambda表達式,無需實現Runnable接口的實現類,簡化代碼。blog
public class ThreadDemo02 { public static void main(String[] args) { new Thread(() -> System.out.println(Thread.currentThread().getName())).start(); } }
有返回值的任務必須實現Callable接口並從新call() 方法,返回值封裝在future中,經過get()方法獲取返回的Object,再結合線程池接口ExecutorService實現有返回值得線程運行。繼承
import java.util.concurrent.*; public class ThreadDemo03 { public static void main(String[] args) { // 建立單個線程的線程池 ExecutorService es = Executors.newSingleThreadExecutor(); // 提交任務到線程池並獲取執行結果 Future<Integer> future = es.submit(new MyThread03()); // 關閉線程池 es.shutdown(); try { if (future.get() != null) { System.out.println("Callable子線程計算結果:" + future.get()); } else { System.out.println("Callable子線程未獲取到結果"); } } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } /** * 實現Callable接口 */ class MyThread03 implements Callable<Integer> { private int sum; @Override public Integer call() throws Exception { System.out.println("Callable子線程開始計算..."); Thread.sleep(1000); for (int i = 0; i < 10; i++) { sum += i; } System.out.println("Callable子線程計算結束..."); return sum; } }
運行結果:接口
正常運行結束:程序運行結束,線程自動結束;
使用退出標誌退出線程:設置一個boolean類型的標誌,經過設置標誌的值終止線程;
public class ThreadTerminatedDemo01 extends Thread{ public volatile boolean exit = false; @Override public void run() { while (!exit) { System.out.println(Thread.currentThread().getName()); } } }
interrupt() 方法中斷線程
public class ThreadTerminatedDemo02 extends Thread{ @Override public void run() { // 非阻塞狀態下經過判斷中斷標誌來退出 while (!isInterrupted()) { try { // 阻塞狀態下捕獲中斷異常來退出 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); // 捕獲到異常後執行break跳出循環 break; } } } }
stop() 方法終止線程(線程不安全)
程序中直接使用Thread.stop()
方法能夠強行終止線程,但會有線程不安全問題。當調用Thread.stop()
方法後,線程拋出ThreadDeathError異常,而且會釋放其持有的全部鎖,從而可能致使數據出現不一致的狀況。
線程之間因爲相互競爭資源或調度不當而同時被阻塞,它們中的一個或所有都在等待某個資源被釋放。
public class ThreadDeadLockDemo { private static Object r1 = new Object(); private static Object r2 = new Object(); public static void main(String[] args) { // Thread01 new Thread(() -> { synchronized (r1) { try { System.out.println(Thread.currentThread().getName() + " has got r1."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r2."); synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); } } }, "Thread01").start(); // Thread02 new Thread(() -> { synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r1."); synchronized (r1) { System.out.println(Thread.currentThread().getName() + " has got r1."); } } }, "Thread02").start(); } }
執行結果:
互斥:該資源任意一個時刻智能由一個線程佔用;
請求保持:一個進程因請求資源而阻塞時不會釋放已經得到的資源;
不可剝奪:一個線程已經得到的資源不能被其它線程強行剝奪,只有等使用結束纔會被釋放;
循環等待:若干進程之間造成一種頭尾相接的循環等待資源關係。
破壞產生死鎖的四個必要條件中的一個。
破壞互斥條件:沒法破壞。
破壞請求保持條件:線程一次性申請全部的資源。
破壞不可剝奪條件:佔用部分資源的線程進一步申請資源時,若是申請不到能夠主動釋放已佔有的資源。
破壞循環等待條件:靠按序申請預防。按某一順序申請資源,釋放資源則反序釋放,破壞循環等待條件。
public class BreakDeadLockDemo { private static Object r1 = new Object(); private static Object r2 = new Object(); public static void main(String[] args) { // Thread01 new Thread(() -> { synchronized (r1) { try { System.out.println(Thread.currentThread().getName() + " has got r1."); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r2."); synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); } } }, "Thread01").start(); // Thread02 new Thread(() -> { synchronized (r1) { System.out.println(Thread.currentThread().getName() + " has got r1."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " is waiting for r1."); synchronized (r2) { System.out.println(Thread.currentThread().getName() + " has got r2."); } } }, "Thread02").start(); } }
對Thread02線程進行修改後,破壞循環等待條件,從而避免死鎖。執行結果以下:
建立一個線程時須要重寫run()方法,調用start()方法後會啓動該線程。調用start()方法會執行線程的相應準備工做而後自動執行run()方法的內容,這是真正的多線程工做。執行run()方法會把run()方法當成main線程下的普通方法去執行,並不會再某個線程中執行,不是多線程的工做。
調用start()方法能夠啓動線程並使該線程進入就緒狀態,而執行run()方法只是線程中的一個普通方法調用,仍在main線程裏執行。