關於線程的內容不少,非一朝一夕可以說完的,java中關於多線程的內容也很多,不要只停留在Thread類和Runnable接口的層面,可是今天簡單體驗Java多線程,主要圍繞Thread和Runnable展開。java
1.首先明確一個概念,在java裏面一個線程只能啓動一次,不然會拋異常的。一個死亡的線程是沒有再次獨立運行的能力。多線程
2.線程的幾種狀態。異步
線程包含以下幾個狀態:初始化、就緒、運行、阻塞、死亡。ide
下面簡單的描述如下這幾個狀態。spa
初始化:建立的Thread類或者其子類對象;線程
就緒:已經完成建立而且初始化的線程對象,而且已經調用start方法了,可是沒有獲取到運行所需的資源(如cup、內存、IO等等)。在java程序中,就是調用了start方法,可是尚未執行run方法的狀態。code
運行:線程對象獲取到了運行所需的資源,而且正在執行任務代碼。對象
阻塞:當前線程仍然是活的,也是能夠運行的,可是缺乏運行的條件,一旦某個事件出現,可以從當前狀態轉爲就緒狀態。(實際上,在這裏描述的仍是太簡單了,在日後的筆記中會詳細說一說這個狀態包含的幾種形態)繼承
死亡:run方法已經執行完了,再也不是一個單獨執行任務的線程了。咱們就認爲其死亡了。接口
3.java中建立線程的幾種方式。
在Java裏面建立線程有三種方式。具體以下:
(1)繼承Thread類
(2)實現Runnable接口
(3)使用Callable與Future來建立
接下來,分別簡單介紹這三種方式。
方式一:繼承Thread類。第一步,繼承Thread類,第二步實現run方法。
* step1:繼承Thread類 * step2:重寫run方法 * @author lingxiasandu * */ public class MyThread extends Thread { @Override public void run() { System.out.println("MyThread is runing !"); } public static void main(String[] args) { MyThread t = new MyThread(); t.start(); } }
方法二:實現Runnable接口。
public class MyThread2 implements Runnable { @Override public void run() { System.out.println("MyThread2 is running !"); } public static void main(String[] args) { MyThread2 runable = new MyThread2(); //和第一種方式的區別,在於啓動線程時,須要依靠一個Thread對象來start Thread t = new Thread(runable); t.start(); } }
第三種:是使用了concurrent包下面的Callable與Future。該種方式適合在有返回值的異步任務。
package hq.java.thread.example; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; /*** * * @author lingxiansandu * */ public class MyTask implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("線程名稱是:"+Thread.currentThread().getName()); System.out.println("MyTask is runing"); return 9; } public static void main(String[] args) throws InterruptedException, ExecutionException { Callable<Integer> call = new MyTask(); FutureTask<Integer> future = new FutureTask<Integer>(call); Thread t = new Thread(future,"帶返回值的線程"); t.start(); System.out.println("線程返回值是:"+future.get()); } }
4.建立並啓動線程常見的寫法。
在實際項目種常見的寫法有如下幾種:
(1)使用匿名類的方式,適用在只有一個地方適用run方法內部的代碼,複用率低的地方。
代碼以下:
new Thread(new Runnable() { @Override public void run() { System.out.println("線程運行了!"); } }).start();
(2)實現Runnable接口,新增一個start方法。這種方式使用於複用率較高的地方,讓使用者忽略線程內部實現,只須要調用start方法就好了。舉個例子,系統在交易時發生異常的時候,向監控平臺發報告,就可使用這種方式。
public class CreateThreadExample { public static void main(String[] args) { SendMoniter.send("1001", "轉帳丟失"); } } class SendMoniter implements Runnable{ private String errorMsg; private String tranId; @Override public void run() { System.out.println("報告監控平臺,交易"+tranId+"有錯誤,錯誤爲:"+errorMsg); } public static void send(String tranId,String errorMsg){ SendMoniter moniter = new SendMoniter(); moniter.errorMsg = errorMsg; moniter.tranId = tranId; Thread t = new Thread(moniter); t.start(); } }
5.線程睡眠的兩種方式。
(1)Thread.sleep(100);
(2) TimeUnit.MILLISECONDS.sleep(1000);//(推薦使用這種)