多執行緒和執行緒池
1.1多執行緒介紹
程序:程序指正在執行的程式。確切的來說,當一個程式進入記憶體執行,即變成一個程序,程序是處於執行過程中的程式,並且具有一定獨立功能
執行緒:執行緒是程序中的一個執行單元,負責當前程序中程式的執行,一個程序中至少有一個執行緒。一個程序中是可以有多個執行緒的,這個應用程式也可以稱之為多執行緒程式。
l單執行緒程式:即,若有多個任務只能依次執行。當上一個任務執行結束後,下一個任務開始執行。如,去網咖上網,網咖只能讓一個人上網,當這個人下機後,下一個人才能上網。
l多執行緒程式:即,若有多個任務可以同時執行。如,去網咖上網,網咖能夠讓多個人同時上網。
1.2Thread類
Thread是程式中的執行執行緒。Java 虛擬機器允許應用程式併發地執行多個執行執行緒。
建立新執行執行緒有兩種方法。
l一種方法是將類宣告為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。建立物件,開啟執行緒。run方法相當於其他執行緒的main方法。
l另一種方法是宣告一個實現 Runnable 介面的類。該類然後實現 run 方法。然後建立Runnable的子類物件,傳入到某個執行緒的構造方法中,開啟執行緒。
1.3建立執行緒方式一繼承Thread類
1 定義一個類繼承Thread。
2 重寫run方法。
3 建立子類物件,就是建立執行緒物件。
4 呼叫start方法,開啟執行緒並讓執行緒執行,同時還會告訴jvm去呼叫run方法。
主程式程式碼
public class Demo01 { public static void main(String[] args) { //建立自定義執行緒物件 MyThread mt = new MyThread("新的執行緒!"); //開啟新執行緒 mt.start(); //在主方法中執行for迴圈 for (int i = 0; i < 10; i++) { System.out.println("main執行緒!"+i); } } }
多執行緒程式程式碼
public class MyThread extends Thread { //定義指定執行緒名稱的構造方法 public MyThread(String name) { //呼叫父類的String引數的構造方法,指定執行緒的名稱 super(name); } /** * 重寫run方法,完成該執行緒執行的邏輯 */ @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(getName()+":正在執行!"+i); } } }
獲取執行緒名稱
lThread.currentThread()獲取當前執行緒物件
lThread.currentThread().getName();獲取當前執行緒物件的名稱
1.4建立執行緒方式—實現Runnable介面
建立執行緒的另一種方法是宣告實現 Runnable 介面的類。該類然後實現 run 方法。然後建立Runnable的子類物件,傳入到某個執行緒的構造方法中,開啟執行緒.
介面中的方法
lThread類構造方法
1、定義類實現Runnable介面。
2、覆蓋介面中的run方法。。
3、建立Thread類的物件
4、將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式。
5、呼叫Thread類的start方法開啟執行緒。
演示程式碼
public class Demo02 { public static void main(String[] args) { //建立執行緒執行目標類物件 Runnable runn = new MyRunnable(); //將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式 Thread thread = new Thread(runn); Thread thread2 = new Thread(runn); //開啟執行緒 thread.start(); thread2.start(); for (int i = 0; i < 10; i++) { System.out.println("main執行緒:正在執行!"+i); } } }
l自定義執行緒執行任務類
public class MyRunnable implements Runnable{ //定義執行緒要執行的run方法邏輯 @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("我的執行緒:正在執行!"+i); } } }
2.1執行緒池概念
執行緒池,其實就是一個容納多個執行緒的容器,其中的執行緒可以反覆使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源.
使用執行緒池方式--Runnable介面
通常,執行緒池都是通過執行緒池工廠建立,再呼叫執行緒池中的方法獲取執行緒,再通過執行緒去執行任務方法。
lExecutors:執行緒池建立工廠類
npublic static ExecutorService newFixedThreadPool(int nThreads):返回執行緒池物件
lExecutorService:執行緒池類
nFuture<?> submit(Runnabletask):獲取執行緒池中的某一個執行緒物件,並執行
lFuture介面:用來記錄執行緒任務執行完畢後產生的結果。執行緒池建立與使用
l使用執行緒池中執行緒物件的步驟:
n建立執行緒池物件
n建立Runnable介面子類物件
n提交Runnable介面子類物件
n關閉執行緒池
程式碼演示
public class ThreadPoolDemo { public static void main(String[] args) { //建立執行緒池物件 ExecutorService service = Executors.newFixedThreadPool(2);//包含2個執行緒物件 //建立Runnable例項物件 MyRunnable r = new MyRunnable(); //自己建立執行緒物件的方式 //Thread t = new Thread(r); //t.start(); ---> 呼叫MyRunnable中的run() //從執行緒池中獲取執行緒物件,然後呼叫MyRunnable中的run() service.submit(r); //再獲取個執行緒物件,呼叫MyRunnable中的run() service.submit(r); service.submit(r); //注意:submit方法呼叫結束後,程式並不終止,是因為執行緒池控制了執行緒的關閉。將使用完的執行緒又歸還到了執行緒池中 //關閉執行緒池 //service.shutdown(); } }
lRunnable介面實現類
public class MyRunnable implements Runnable { @Override public void run() { System.out.println("我要一個教練"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("教練來了: " +Thread.currentThread().getName()); System.out.println("教我游泳,交完後,教練回到了游泳池"); } }
使用執行緒池方式—Callable介面
lCallable介面:與Runnable介面功能相似,用來指定執行緒的任務。其中的call()方法,用來返回執行緒任務執行完畢後的結果,call方法可丟擲異常。
lExecutorService:執行緒池類
n<T> Future<T> submit(Callable<T>task):獲取執行緒池中的某一個執行緒物件,並執行執行緒中的call()方法
lFuture介面:用來記錄執行緒任務執行完畢後產生的結果。執行緒池建立與使用
l使用執行緒池中執行緒物件的步驟:
n建立執行緒池物件
n建立Callable介面子類物件
n提交Callable介面子類物件
n關閉執行緒池
程式碼演示
public class ThreadPoolDemo { public static void main(String[] args) { //建立執行緒池物件 ExecutorService service = Executors.newFixedThreadPool(2);//包含2個執行緒物件 //建立Callable物件 MyCallable c = new MyCallable(); //從執行緒池中獲取執行緒物件,然後呼叫MyRunnable中的run() service.submit(c); //再獲取個教練 service.submit(c); service.submit(c); //注意:submit方法呼叫結束後,程式並不終止,是因為執行緒池控制了執行緒的關閉。將使用完的執行緒又歸還到了執行緒池中 //關閉執行緒池 //service.shutdown(); } }
lCallable介面實現類,call方法可丟擲異常、返回執行緒任務執行完畢後的結果
public class MyCallable implements Callable { @Override public Object call() throws Exception { System.out.println("我要一個教練:call"); Thread.sleep(2000); System.out.println("教練來了: " +Thread.currentThread().getName()); System.out.println("教我游泳,交完後,教練回到了游泳池"); return null; } }
l測試類
public class Demo01 {
public static void main(String[] args) {
//建立自定義執行緒物件
MyThread mt = new MyThread("新的執行緒!");
//開啟新執行緒
mt.start();
//在主方法中執行for迴圈
for (int i = 0; i < 10; i++) {
System.out.println("main執行緒!"+i);
}
}
}
l自定義執行緒類
public class MyThread extends Thread {
//定義指定執行緒名稱的構造方法
public MyThread(String name) {
//呼叫父類的String引數的構造方法,指定執行緒的名稱
super(name);
}
/**
* 重寫run方法,完成該執行緒執行的邏輯
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+":正在執行!"+i);
}
}
}