您好,登錄后才能下訂單哦!
這篇文章主要介紹“java中的線程怎么理解”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“java中的線程怎么理解”文章能幫助大家解決問題。
線程(thread)是一個程序內部的一條執行路徑,我們所熟悉的main方法其實就是一條單獨執行路徑,若程序中只有一條執行路徑那么這個程序就是單線程程序;既然有單線程,那么也相對的會有多線程,字面意思可以理解為“相對單線程從軟硬件上多條執行流程的技術”,多線程的好處是提高CPU的利用率。 在多線程程序中,一個線程必須等待的時候,CPU可以運行其它的線程而不是等待,大大提高程序的效率。
方式一創建過程:
定義一個子類MyThread繼承線程類java.lang.Thread,重寫run()方法;
創建MyThread類的對象;
調用線程對象的start()方法啟動線程(啟動后仍然執行run()方法);
public class ThreadDemo01 { public static void main(String[] args) { MyThread myThread1 = new MyThread(); myThread1.start(); for (int i = 0; i < 3; i++) { System.out.println("主線程正在執行~~"); } } } class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println("子線程正在執行~~"); } } } //輸出結果(不唯一): //主線程正在執行~~ //主線程正在執行~~ //主線程正在執行~~ //子線程正在執行~~ //子線程正在執行~~ //子線程正在執行~~
在以上代碼中共有兩個線程在執行,分別是main方法的主線程和線程對象mythread調用start()啟動的子線程。不過輸出結果為什么會不唯一的呢?原因是因為兩個線程在執行過程中會發生CPU的搶占,誰先搶到誰將優先執行。
那么我們為什么不直接使用線程對象調用run()方法呢?若直接調用run()則只是普通的調用方法,即單線程,而start()方法則是用來啟動的子線程的,由此才能出現多線程。
方式一優缺點:
優點:編碼簡單;
缺點:線程類已經繼承Thread,無法繼承其他類,不利于擴展;
方式二創建過程:
1、定義一個線程任務類MyRunnable實現Runnable接口,重寫run()方法;
2、創建MyRunnable對象;
3、把MyRunnable任務對象交給Thread處理;
4、調用線程對象的start()方法啟動線程;
Thread構造器 | 方法 |
public Thread (String name) | 可以為當前線程指定名稱 |
public Thread (Runnable target) | 封裝Runnable對象成為線程對象 |
public Thread (Runnable target ,String name) | 封裝Runnable對象成為線程對象,并指定線程名稱 |
public class ThreadDemo02 { public static void main(String[] args) { MyRunnable target = new MyRunnable(); Thread thread = new Thread(target); thread.start(); for (int i = 0; i < 3; i++) { System.out.println("主線程正在執行~~"); } } } class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println("子線程正在執行~~"); } } } //輸出結果(不唯一): //主線程正在執行~~ //子線程正在執行~~ //子線程正在執行~~ //子線程正在執行~~ //主線程正在執行~~ //主線程正在執行~~
該代碼與方式一的不同之處在于需要將MyRunnable任務對象封裝在Thread中,其他的地方是基本上是沒有變化的。
方式二優缺點:
優點:線程任務類只是實現接口,可以繼續繼承類和實現接口,擴展性強;
缺點:編程多一層對象包裝,如果線程有執行結果是不可以直接返回的。
接下來我們同樣使用實現Runnable接口(匿名內部類形式)來實現多線程的創建:
1、創建Runnable匿名內部類對象;
2、交給Thread處理;
3、調用線程對象的start()啟動線程;
//正常版: public class ThreadDemo01 { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println("子線程正在執行~~"); } } }); thread.start(); for (int i = 0; i < 3; i++) { System.out.println("主線程正在執行~~"); } } } //lambda簡化版: new Thread(()-> { for (int i = 0; i < 3; i++) { System.out.println("子線程正在執行~~"); } }).start();
該種方法從本質上其實并沒有太大的區別只不過是一個需要創建線程對象,而另一個則是通過匿名內部類實現的多線程。并且該塊代碼也可以通過lambda表達式進行精簡,不知道大家是否還對這個知識點有印象呢?若忘記了可以看一下這篇文章:Java中的lambda表達式如何理解——精簡
在學習過前面兩種創建多線程的方式以后,我們會發現存在一個問題:1、重寫的run()方法不能直接返回結果;2、不適合需要返回線程執行結果的業務場景。因此,我們需要第三種方式來解決這些問題。
方式三創建過程:
1、定義類實現Callable接口,重寫call()方法,封裝要做的事情;
2、用FutureTask把Callable對象封裝成線程任務對象;
3、把線程任務對象交給Thread處理;
4、調用Thread的start()方法啟動線程,執行任務;
5、線程執行完畢后,通過FutureTask的get()方法獲取任務執行的結果。
方法名稱 | 說明 |
public FutureTask<>(Callable call) | 把Callable對象封裝成FutureTask對象 |
public V get() throws Exception | 獲取線程執行call方法返回的結果 |
public class ThreadDemo03 { public static void main(String[] args) throws Exception { MyCallable myCallable = new MyCallable(); FutureTask<String> futureTask = new FutureTask<>(myCallable); Thread thread = new Thread(futureTask); thread.start(); int sum= 0; for (int i = 0; i < 3; i++) { sum+=i; } System.out.println(sum); String s =futureTask.get(); System.out.println(s); } } class MyCallable implements Callable<String > { @Override public String call(){ int sum=0; for (int i = 0; i < 3; i++) { sum+=i; } return "子線程計算結果:"+sum; } } //輸出結果: //3 //子線程計算結果:3
方式三優缺點:
優點:
線程任務類只是實現接口,可以繼續繼承類和實現接口,擴展性強;
可以在線程執行完畢后去獲取 線程執行的結果;
缺點:
編碼復雜一點;
方式 | 優點 | 缺點 |
繼承Thread類 | 編程比較簡單,可以直接使用Thread類中的方法 | 擴展性較差,不能再繼承其他的類,不能返回線程執行的結果 |
實現Runnable接口 | 擴展性強,實現該接口的同時還可以繼承其他的類 | 編程相對復雜,不能返回線程執行的結果 |
實現Callable接口 | 擴展性強,實現該接口的同時還可以繼承其他的類,可以得到線程的執行結果 | 編程相對復雜 |
方法名稱 | 說明 |
String getName() | 獲取當前線程的名稱,默認線程名稱是Thread-索引 |
void setName(String name) | 將此線程更改為指定的名稱,通過構造器也可以設置線程名稱 |
簡單地通過一段代碼讓大家能夠清晰地了解這個代碼該如何使用:
public class ThreadDemo04 { public static void main(String[] args) throws Exception { thread thread1 = new thread(); thread1.setName("1號子線程"); thread1.start(); thread thread2 = new thread(); thread2.setName("2號子線程"); thread2.start(); } } class thread extends Thread { @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println(this.getName()+"正在執行任務"+i); } } } //輸出結果: //2號子線程正在執行任務0 //1號子線程正在執行任務0 //2號子線程正在執行任務1 //1號子線程正在執行任務1 //2號子線程正在執行任務2 //1號子線程正在執行任務2
方法名稱 | 說明 |
public static void sleep(long time) | 讓當前線程休眠指定的時間后再繼續執行,單位為毫秒 |
public class ThreadDemo05 { public static void main(String[] args) throws Exception { for (int i = 0; i < 5; i++) { System.out.println(i); if (i==3){ Thread.sleep(5000); } } } } //輸出結果: //1 //2 //3 //在輸出過3以后,等待5秒之后再進行輸出 //4
關于“java中的線程怎么理解”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。