這篇文章主要介紹“java中的線程怎么理解”的相關(guān)知識(shí),小編通過(guò)實(shí)際案例向大家展示操作過(guò)程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“java中的線程怎么理解”文章能幫助大家解決問(wèn)題。
專注于為中小企業(yè)提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)鼓樓免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了成百上千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
線程(thread)是一個(gè)程序內(nèi)部的一條執(zhí)行路徑,我們所熟悉的main方法其實(shí)就是一條單獨(dú)執(zhí)行路徑,若程序中只有一條執(zhí)行路徑那么這個(gè)程序就是單線程程序;既然有單線程,那么也相對(duì)的會(huì)有多線程,字面意思可以理解為“相對(duì)單線程從軟硬件上多條執(zhí)行流程的技術(shù)”,多線程的好處是提高CPU的利用率。 在多線程程序中,一個(gè)線程必須等待的時(shí)候,CPU可以運(yùn)行其它的線程而不是等待,大大提高程序的效率。
方式一創(chuàng)建過(guò)程:
定義一個(gè)子類MyThread繼承線程類java.lang.Thread,重寫run()方法;
創(chuàng)建MyThread類的對(duì)象;
調(diào)用線程對(duì)象的start()方法啟動(dòng)線程(啟動(dòng)后仍然執(zhí)行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("主線程正在執(zhí)行~~"); } } } class MyThread extends Thread{ @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println("子線程正在執(zhí)行~~"); } } } //輸出結(jié)果(不唯一): //主線程正在執(zhí)行~~ //主線程正在執(zhí)行~~ //主線程正在執(zhí)行~~ //子線程正在執(zhí)行~~ //子線程正在執(zhí)行~~ //子線程正在執(zhí)行~~
在以上代碼中共有兩個(gè)線程在執(zhí)行,分別是main方法的主線程和線程對(duì)象mythread調(diào)用start()啟動(dòng)的子線程。不過(guò)輸出結(jié)果為什么會(huì)不唯一的呢?原因是因?yàn)閮蓚€(gè)線程在執(zhí)行過(guò)程中會(huì)發(fā)生CPU的搶占,誰(shuí)先搶到誰(shuí)將優(yōu)先執(zhí)行。
那么我們?yōu)槭裁床恢苯邮褂镁€程對(duì)象調(diào)用run()方法呢?若直接調(diào)用run()則只是普通的調(diào)用方法,即單線程,而start()方法則是用來(lái)啟動(dòng)的子線程的,由此才能出現(xiàn)多線程。
方式一優(yōu)缺點(diǎn):
優(yōu)點(diǎn):編碼簡(jiǎn)單;
缺點(diǎn):線程類已經(jīng)繼承Thread,無(wú)法繼承其他類,不利于擴(kuò)展;
方式二創(chuàng)建過(guò)程:
1、定義一個(gè)線程任務(wù)類MyRunnable實(shí)現(xiàn)Runnable接口,重寫run()方法;
2、創(chuàng)建MyRunnable對(duì)象;
3、把MyRunnable任務(wù)對(duì)象交給Thread處理;
4、調(diào)用線程對(duì)象的start()方法啟動(dòng)線程;
Thread構(gòu)造器 | 方法 |
public Thread (String name) | 可以為當(dāng)前線程指定名稱 |
public Thread (Runnable target) | 封裝Runnable對(duì)象成為線程對(duì)象 |
public Thread (Runnable target ,String name) | 封裝Runnable對(duì)象成為線程對(duì)象,并指定線程名稱 |
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("主線程正在執(zhí)行~~"); } } } class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println("子線程正在執(zhí)行~~"); } } } //輸出結(jié)果(不唯一): //主線程正在執(zhí)行~~ //子線程正在執(zhí)行~~ //子線程正在執(zhí)行~~ //子線程正在執(zhí)行~~ //主線程正在執(zhí)行~~ //主線程正在執(zhí)行~~
該代碼與方式一的不同之處在于需要將MyRunnable任務(wù)對(duì)象封裝在Thread中,其他的地方是基本上是沒(méi)有變化的。
方式二優(yōu)缺點(diǎn):
優(yōu)點(diǎn):線程任務(wù)類只是實(shí)現(xiàn)接口,可以繼續(xù)繼承類和實(shí)現(xiàn)接口,擴(kuò)展性強(qiáng);
缺點(diǎn):編程多一層對(duì)象包裝,如果線程有執(zhí)行結(jié)果是不可以直接返回的。
接下來(lái)我們同樣使用實(shí)現(xiàn)Runnable接口(匿名內(nèi)部類形式)來(lái)實(shí)現(xiàn)多線程的創(chuàng)建:
1、創(chuàng)建Runnable匿名內(nèi)部類對(duì)象;
2、交給Thread處理;
3、調(diào)用線程對(duì)象的start()啟動(dòng)線程;
//正常版: 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("子線程正在執(zhí)行~~"); } } }); thread.start(); for (int i = 0; i < 3; i++) { System.out.println("主線程正在執(zhí)行~~"); } } } //lambda簡(jiǎn)化版: new Thread(()-> { for (int i = 0; i < 3; i++) { System.out.println("子線程正在執(zhí)行~~"); } }).start();
該種方法從本質(zhì)上其實(shí)并沒(méi)有太大的區(qū)別只不過(guò)是一個(gè)需要?jiǎng)?chuàng)建線程對(duì)象,而另一個(gè)則是通過(guò)匿名內(nèi)部類實(shí)現(xiàn)的多線程。并且該塊代碼也可以通過(guò)lambda表達(dá)式進(jìn)行精簡(jiǎn),不知道大家是否還對(duì)這個(gè)知識(shí)點(diǎn)有印象呢?若忘記了可以看一下這篇文章:Java中的lambda表達(dá)式如何理解——精簡(jiǎn)
在學(xué)習(xí)過(guò)前面兩種創(chuàng)建多線程的方式以后,我們會(huì)發(fā)現(xiàn)存在一個(gè)問(wèn)題:1、重寫的run()方法不能直接返回結(jié)果;2、不適合需要返回線程執(zhí)行結(jié)果的業(yè)務(wù)場(chǎng)景。因此,我們需要第三種方式來(lái)解決這些問(wèn)題。
方式三創(chuàng)建過(guò)程:
1、定義類實(shí)現(xiàn)Callable接口,重寫call()方法,封裝要做的事情;
2、用FutureTask把Callable對(duì)象封裝成線程任務(wù)對(duì)象;
3、把線程任務(wù)對(duì)象交給Thread處理;
4、調(diào)用Thread的start()方法啟動(dòng)線程,執(zhí)行任務(wù);
5、線程執(zhí)行完畢后,通過(guò)FutureTask的get()方法獲取任務(wù)執(zhí)行的結(jié)果。
方法名稱 | 說(shuō)明 |
public FutureTask<>(Callable call) | 把Callable對(duì)象封裝成FutureTask對(duì)象 |
public V get() throws Exception | 獲取線程執(zhí)行call方法返回的結(jié)果 |
public class ThreadDemo03 { public static void main(String[] args) throws Exception { MyCallable myCallable = new MyCallable(); FutureTaskfutureTask = 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 { @Override public String call(){ int sum=0; for (int i = 0; i < 3; i++) { sum+=i; } return "子線程計(jì)算結(jié)果:"+sum; } } //輸出結(jié)果: //3 //子線程計(jì)算結(jié)果:3
方式三優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
線程任務(wù)類只是實(shí)現(xiàn)接口,可以繼續(xù)繼承類和實(shí)現(xiàn)接口,擴(kuò)展性強(qiáng);
可以在線程執(zhí)行完畢后去獲取 線程執(zhí)行的結(jié)果;
缺點(diǎn):
編碼復(fù)雜一點(diǎn);
方式 | 優(yōu)點(diǎn) | 缺點(diǎn) |
繼承Thread類 | 編程比較簡(jiǎn)單,可以直接使用Thread類中的方法 | 擴(kuò)展性較差,不能再繼承其他的類,不能返回線程執(zhí)行的結(jié)果 |
實(shí)現(xiàn)Runnable接口 | 擴(kuò)展性強(qiáng),實(shí)現(xiàn)該接口的同時(shí)還可以繼承其他的類 | 編程相對(duì)復(fù)雜,不能返回線程執(zhí)行的結(jié)果 |
實(shí)現(xiàn)Callable接口 | 擴(kuò)展性強(qiáng),實(shí)現(xiàn)該接口的同時(shí)還可以繼承其他的類,可以得到線程的執(zhí)行結(jié)果 | 編程相對(duì)復(fù)雜 |
方法名稱 | 說(shuō)明 |
String getName() | 獲取當(dāng)前線程的名稱,默認(rèn)線程名稱是Thread-索引 |
void setName(String name) | 將此線程更改為指定的名稱,通過(guò)構(gòu)造器也可以設(shè)置線程名稱 |
簡(jiǎn)單地通過(guò)一段代碼讓大家能夠清晰地了解這個(gè)代碼該如何使用:
public class ThreadDemo04 { public static void main(String[] args) throws Exception { thread thread1 = new thread(); thread1.setName("1號(hào)子線程"); thread1.start(); thread thread2 = new thread(); thread2.setName("2號(hào)子線程"); thread2.start(); } } class thread extends Thread { @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println(this.getName()+"正在執(zhí)行任務(wù)"+i); } } } //輸出結(jié)果: //2號(hào)子線程正在執(zhí)行任務(wù)0 //1號(hào)子線程正在執(zhí)行任務(wù)0 //2號(hào)子線程正在執(zhí)行任務(wù)1 //1號(hào)子線程正在執(zhí)行任務(wù)1 //2號(hào)子線程正在執(zhí)行任務(wù)2 //1號(hào)子線程正在執(zhí)行任務(wù)2
方法名稱 | 說(shuō)明 |
public static void sleep(long time) | 讓當(dāng)前線程休眠指定的時(shí)間后再繼續(xù)執(zhí)行,單位為毫秒 |
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); } } } } //輸出結(jié)果: //1 //2 //3 //在輸出過(guò)3以后,等待5秒之后再進(jìn)行輸出 //4
關(guān)于“java中的線程怎么理解”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。