這篇文章主要介紹了java 多線程的三種構建方法的相關資料,這裡提供三種實現方法,希望大家能夠掌握,很重要的基礎知識,需要的朋友可以參考下
java 多執行緒的三種建置方法
繼承Thread類別建立執行緒類別
public class Thread extends Object implements Runnable
定義Thread類別的子類,並重寫其run()方法
#建立Thread子類別的實例,即建立了執行緒物件
呼叫執行緒物件的start()方法啟動執行緒
public class FirstThread extends Thread { public void run(){ for(int i=0;i<100;i++){ /* * Thread类已经继承了Object * Object类创建了name选项 并且有其getName(),setName()方法 * 在继承Thread的类里面使用时只需要用this引用 */ System.out.println(this.getName()+" "+i); } } public static void main(String[] args) { for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+" "+i); if(i==20){ new FirstThread().start(); new FirstThread().start(); } } } }
Thread類別已經繼承了Object
Object類別建立了name選項並且有其getName(),setName()方法
#在繼承Thread的類別裡面使用時只需要用this引用
上面兩個副線程和主線程隨機切換,又因為使用的是繼承Thread的類別所以兩個副線程不能共享資源
start()方法調用後並不是立即執行多線程程式碼,而是使得該執行緒程式設計可運行狀態,何時運行是由作業系統決定的
#實作Runnable介面建立執行緒類別
public Thread() public Thread(Runnable target) public Thread(Runnable target,String name)
定義Runnable介面的實作類,並重寫該介面的run()方法
建立Runnable實作類的實例,並以此作為Thread的target來創建Thread對象,該Thread對象才是真正的線程對象。
public class SecondThread implements Runnable { public void run(){ for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+" "+i); } } public static void main(String[] args) { for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+" "+i); if(i==20){ SecondThread st=new SecondThread(); //通过new Thread(target,name)创建线程 new Thread(st,"新线程1").start(); new Thread(st,"新线程2").start(); } } } }
上面的結果是兩個副執行緒和主執行緒隨機切換,但是並沒有共享資源,因為他們根本沒有能用來共享的資源。
start()方法呼叫後並不是立即執行多執行緒程式碼,而是使得該執行緒程式設計可運行狀態,什麼時候運行是由作業系統決定的
繼承Thread類別和創建Runnable介面的共享資源詳解
在只有可以用來共享的資源時候,也就是同用一個實例化物件。兩個建立方式在共享資源時才會有所區別,否則它們都不會共享資源共享資源通常用private static 修飾符來修飾。
class Thread1 extends Thread{ private int count=5; private String name; public Thread1(String name) { this.name=name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 count= " + count--); try { sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) { Thread1 mTh1=new Thread1("A"); Thread1 mTh2=new Thread1("B"); mTh1.start(); mTh2.start(); } }
B运行 count= 5 A运行 count= 5 B运行 count= 4 B运行 count= 3 B运行 count= 2 B运行 count= 1 A运行 count= 4 A运行 count= 3 A运行 count= 2 A运行 count= 1
正是因為有了private int count=5;一句才有了共享資源,但這是繼承Thread類的子類,並不能共享資源
class Thread2 implements Runnable{ private int count=15; public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "运行 count= " + count--); try { Thread.sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) { Thread2 my = new Thread2(); new Thread(my, "C").start();//同一个mt,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常 new Thread(my, "D").start(); new Thread(my, "E").start(); } }
C运行 count= 15 D运行 count= 14 E运行 count= 13 D运行 count= 12 D运行 count= 10 D运行 count= 9 D运行 count= 8 C运行 count= 11 E运行 count= 12 C运行 count= 7 E运行 count= 6 C运行 count= 5 E运行 count= 4 C运行 count= 3 E运行 count= 2
同樣的正是因為有了private int count=15這個共同的實例化對象,實作Runnable的類別才可以共享資源
那為什麼繼承Thread類別的子類別實作Runable介面的類別在共享資源時有差別呢?
因為Java只能支援單繼承,單繼承特點意味著只能有一個子類去繼承而Runnabl接口後可以跟好多類,便可以進行多個線程共享一個資源的操作
使用Callable和Future建立執行緒
#Callable怎麼看起來都像Runnable介面的增強版,Callable有一個call()方法相當於Runnable的run()方法,但是功能更加強大:
call()方法可以有回傳值
call()方法可以宣告拋出例外
Callable介面有泛型限制,Callable介面裡的泛型形參類型與call()方法的回傳值類型相同。 而且Callable介面是函數式接口,因此可使用Lambda表達式建立Callable物件Runnable介面也是函數式接口,因此也可以使用Lambda表達式建立Runnable物件
#建立Callable介面的實作類,並實作call()方法,該call()方法將作為執行緒執行體,再建立Callable實作類別的實例
使用FutureTask類別物件作為Thread物件的target建立並啟動新執行緒
呼叫FutureTask物件的get()方法來取得子執行緒結束後的回傳值
public class ThirdThread implements Callable<Integer> { public Integer call(){ int i=0; for(;i<100;i++){ System.out.println(Thread.currentThread().getName()+" "+i); } return i; } public static void main(String[] args){ ThirdThread tt=new ThirdThread(); FutureTask<Integer> task=new FutureTask<>(tt); Thread t=new Thread(task,"有返回值的线程"); for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+" "+i); if(i==20){ t.start(); } } try{ System.out.println("返回值是:"+task.get()); }catch(Exception e){ e.printStackTrace(); } } }
public class ThirdThread{ public static void main(String[] args){ ThirdThread tt=new ThirdThread(); //先使用Lambda表达式创建Callable<Integer>对象 //使用FutureTask封装Callable对象 FutureTask<Integer> task=new FutureTask<Integer>((Callable<Integer>)()->{ int i=0; for(;i<100;i++){ System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i); } return i; }); for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName()+"的循环变量i的值:"+i); if(i==20){ new Thread(task,"有返回值的线程").start(); } } try{ System.out.println("子线程的返回值"+task.get()); }catch(Exception e){ e.printStackTrace(); } } }
以上是Java中使用三種建構多執行緒的方法來分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!