多執行緒,,,,,執行緒池
多執行緒
1. Thread類
建立新執行執行緒有兩種方法。
l 一種方法是將類宣告為 Thread 的子類。該子類應重寫 Thread 類的 run 方法。建立物件,開啟執行緒。run方法相當於其他執行緒的main方法。
l 另一種方法是宣告一個實現 Runnable 介面的類。該類然後實現 run 方法。然後建立Runnable的子類物件,傳入到某個執行緒的構造方法中,開啟執行緒。
繼承Thread,重寫run方法
public class MyThread extends Thread{ public void run() {//重寫,描述執行緒任務 for(int i=0;i<100;i++){ System.out.println("MyThread:"+i); } } }
測試
public class Demo02 {//多執行緒程式同時進行 public static void main(String[] args) { //建立執行緒物件 MyThread my=new MyThread(); my.start();//開啟執行緒,start呼叫的是Thread類中的run方法 for(int i=0;i<100;i++){ System.out.println("main:"+i); } } }
兩個迴圈同時進行,交叉列印,因為調start方法時會開一個新棧,兩個棧交替執行
獲取執行緒名稱
l Thread.currentThread()獲取當前執行緒物件
l Thread.currentThread().getName();獲取當前執行緒物件的名稱
public class Demo02 {//多執行緒程式同時進行 public static void main(String[] args) { //建立執行緒物件 MyThread my=new MyThread(); my.start();//開啟執行緒 for(int i=0;i<100;i++){ //先獲得執行緒物件,再獲取執行緒名稱 System.out.println(Thread.currentThread().getName()+":"+i); } } }
public class MyThread extends Thread{ public void run() { //重寫,描述執行緒任務 for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i);//獲取執行緒名稱 } } }
建立執行緒方式—實現Runnable介面
Runnable介面用來指定每個執行緒要執行的任務。包含了一個 run 的無引數抽象方法,需要由介面實現類重寫該方法。
l Thread類構造方法
建立執行緒的步驟。
1、定義類實現Runnable介面。
2、覆蓋介面中的run方法。。
3、建立Thread類的物件
4、將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式。
5、呼叫Thread類的start方法開啟執行緒。
public class Demo01 { public static void main(String[] args) { //建立執行緒執行目標物件 MyRunnable my=new MyRunnable(); //將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式 Thread th=new Thread(my); //開啟執行緒 th.start(); //主執行緒任務 for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
public class MyRunnable implements Runnable { //定義執行緒要執行的run方法邏輯 public void run() { for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
實現Runnable的原理
實現Runnable介面,避免了繼承Thread類的單繼承侷限性。覆蓋Runnable介面中的run方法,將執行緒任務程式碼定義到run方法中。
建立Thread類的物件,只有建立Thread類的物件才可以建立執行緒。執行緒任務已被封裝到Runnable介面的run方法中,而這個run方法所屬於Runnable介面的子類物件,所以將這個子類物件作為引數傳遞給Thread的建構函式,這樣,執行緒物件建立時就可以明確要執行的執行緒的任務。
實現Runnable的好處
現Runnable介面避免了單繼承的侷限性,所以較為常用。實現Runnable介面的方式,更加的符合面向物件,執行緒分為兩部分,一部分執行緒物件,一部分執行緒任務。
執行緒的匿名內部類使用
匿名內部類格式:new父類或介面(){ 重寫父類方法 }
使用執行緒的內匿名內部類方式,可以方便的實現每個執行緒執行不同的執行緒任務操作。
public class Demo02 { public static void main(String[] args) { //繼承Thread類的匿名內部類物件 //new父類(){重寫父類方法} Thread t=new Thread(){//多型,得到父類的子類物件 public void run() { for(int i=1;i<10;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }; t.start(); //實現runable介面 //建立執行緒任務物件 Runnable my=new Runnable(){ public void run() { for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+":::"+i); } }; }; //建立執行緒物件,交替執行 new Thread(my).start(); } }
執行緒池
執行緒池概念
執行緒池,其實就是一個容納多個執行緒的容器,其中的執行緒可以反覆使用,省去了頻繁建立執行緒物件的操作,無需反覆建立執行緒而消耗過多資源。
使用執行緒池方式--Runnable介面
l Executors:執行緒池建立工廠類
public static ExecutorService newFixedThreadPool(int nThreads):返回執行緒池物件
l ExecutorService:執行緒池類
Future<?> submit(Runnabletask):獲取執行緒池中的某一個執行緒物件,並執行
l Future介面:用來記錄執行緒任務執行完畢後產生的結果。執行緒池建立與使用
l 使用執行緒池中執行緒物件的步驟:
建立執行緒池物件
建立Runnable介面子類物件
提交Runnable介面子類物件
關閉執行緒池
public class Demo03 { public static void main(String[] args) { //獲取執行緒池物件 ExecutorService es=Executors.newFixedThreadPool(2); //建立執行緒任務物件 MyRunnable r=new MyRunnable(); //執行執行緒任務,如果執行緒任務大於執行緒數,就排隊執行 es.submit(r); es.submit(r); //銷燬執行緒池 es.shutdown(); } }
l Runnable介面實現類
public class MyRunnable implements Runnable { //定義執行緒要執行的run方法邏輯 public void run() { for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+":"+i); } } }
使用執行緒池方式—Callable介面
l Callable介面:與Runnable介面功能相似,用來指定執行緒的任務。其中的call()方法,用來返回執行緒任務執行完畢後的結果,call方法可丟擲異常。
l ExecutorService:執行緒池類
<T> Future<T> submit(Callable<T>task):獲取執行緒池中的某一個執行緒物件,並執行執行緒中的call()方法
l Future介面:用來記錄執行緒任務執行完畢後產生的結果。執行緒池建立與使用
l 使用執行緒池中執行緒物件的步驟:
建立執行緒池物件
建立Callable介面子類物件
提交Callable介面子類物件
關閉執行緒池
public class Demo04 { public static void main(String[] args) throws InterruptedException, ExecutionException { //建立執行緒池物件 ExecutorService es=Executors.newFixedThreadPool(2); //建立Callable物件 MyCallable c=new MyCallable(); //執行執行緒任務 //從執行緒池中獲取執行緒物件,然後呼叫MyRunnable中的run() Future<String> f=es.submit(c); //注意:submit方法呼叫結束後,程式並不終止, //是因為執行緒池控制了執行緒的關閉。將使用完的執行緒又歸還到了執行緒池中 //獲取返回值 String mes=f.get(); System.out.println(mes); es.shutdown(); } }
l Callable介面實現類,call方法可丟擲異常、返回執行緒任務執行完畢後的結果
public class MyCallable implements Callable<String>{ public String call() throws Exception { return "abc"; } }
練習
用兩條執行緒分別計算1-50的和 和1-100的和,將結果返回
public class Demo01 { public static void main(String[] args) throws InterruptedException, ExecutionException { //用兩條執行緒分別計算1-50的和 和1-100的和,將結果返回 //獲取執行緒池物件 ExecutorService es=Executors.newFixedThreadPool(2); //建立執行緒任務 Call c1=new Call(100); Call c2=new Call(50); //執行 Future<Integer> f1=es.submit(c1); Future<Integer> f2=es.submit(c2); //獲取返回值 System.out.println(f1.get()); System.out.println(f2.get()); //銷燬執行緒池 es.shutdown(); } }
public class Call implements Callable<Integer>{ private int num; public Call(int num){ this.num=num; } public Integer call() throws Exception { int sum=0; for(int i=1;i<=num;i++){ sum=sum+i; } return sum; } }