文章目錄
- 1.什么是線程
- 2. 線程創建和運行
1.什么是線程
進程是操作系統進行資源分配和調度的基本單位,線程是 CPU 分配的基本單位。
- 程序計數器用來記錄線程當前要執行的指令地址。CPU一般是使用時間片輪轉方式讓線程輪詢占用的,程序計數器是記錄線程讓出CPU時的執行地址的,待再次分配到時間片時線程就可以從自己私有的計數器指定地址繼續執行。另外需要注意的是,如果執行的是 native 方法那么 pc計數器記錄的是 undefned 地址,只有執行的是 Java 代碼時 pc計數器記錄的才是下一條指令的地址。
- 棧用于存儲線程的局部變量,調用棧幀。
- 堆里面主要存放 new創建的對象實例。
- 方法區存放 加載的類、常量及靜態變量等信息。
2. 線程創建和運行
java中創建線程的三種方式:繼承Thread類,實現Runnable接口,實現Callable接口 。
- 繼承Thread類
public class MyThread extends Thread{@Overridepublic void run() {System.out.println (" I am a child thread,線程id:"+this.getId()+"線程名字:"+this.getName()) ;System.out.println (" I am a child thread,線程id:"+Thread.currentThread().getId()+"線程名字:"+Thread.currentThread().getName()) ;System.out.println (System.getProperty("java.version")+","+System.getProperty("java.vendor")+","+System.getProperty("java.vendor.url"));}public static void main(String[] args) {MyThread thread= new MyThread();//創建線程thread.start();// 啟動線程}
}
- 實現Runnable接口
public class RunableTask implements Runnable{@Overridepublic void run() {System.out.println (" I am a child thread,線程id:"+Thread.currentThread().getId()+"線程名字:"+Thread.currentThread().getName()) ;}public static void main(String[] args) {RunableTask task = new RunableTask();new Thread(task).start() ;new Thread(task).start() ;}
}
- 實現Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallerTask implements Callable<String> {@Overridepublic String call() throws Exception {return "hello";}public static void main(String[] args) {// 創建異步任務FutureTask<String> futureTask=new FutureTask<>(new CallerTask()) ;//啟動線程new Thread(futureTask).start() ;try { //等待任務執行完畢,并返回結果String result = futureTask.get();System.out.println(result);} catch (ExecutionException | InterruptedException e){e.printStackTrace();}}
}
調用了start方法后才真正啟動了線程。其實調用start方法后線程并沒有馬上執行而是處于就緒狀態,這個就緒狀態是指該線程已經獲取了除 CPU 資源外的其他資源,等待獲取 CPU 資源后才會真正處于運行狀態。一旦 run 方法執行完畢,該線程就處于終止狀態。
使用繼承方式的好處是,在run()方法內獲取當前線程直接使用this就可以了,無須使用 Thread.currentThread()方法;不好的地方是Java不支持多繼承,繼承了 Thread 類不能繼承其他類。另外任務與代碼沒分離,多個線程執行一樣的任務時需要多份任務代碼。
Runable接口實現的,兩個線程可以共用一個 task 代碼邏輯,可以給RunableTask添加參數進行任務區分。
Callable 接口實現的任務有返回值,通過futureTask.get()等待任務執行完畢并返回結果。