廣州市做企業(yè)網(wǎng)站東莞seo培訓(xùn)
1、什么是線程
? ? ? ? 線程(Thread)是一條程序內(nèi)部的一條執(zhí)行流程。
????????程序中如果只有一條執(zhí)行流程,那這個(gè)程序就是單線程的程序。
2、什么是多線程
? ? ? ? 多線程(multithreading),是指從軟件或者硬件上實(shí)現(xiàn)多個(gè)線程并發(fā)執(zhí)行的技術(shù)。具有多線程能力的計(jì)算機(jī)因有硬件支持而能夠在同一時(shí)間執(zhí)行多于一個(gè)線程,進(jìn)而提升整體處理性能。具有這種能力的系統(tǒng)包括對(duì)稱多處理機(jī)、多核心處理器以及芯片級(jí)多處理或同時(shí)多線程處理器。在一個(gè)程序中,這些獨(dú)立運(yùn)行的程序片段叫作“線程”(Thread),利用它編程的概念就叫作“多線程處理“。
3、多線程的優(yōu)缺點(diǎn)
3.1、優(yōu)點(diǎn)
- 同時(shí)執(zhí)行多個(gè)任務(wù),提高程序的工作效率。
- 提高CPU的使用率。
- 線程之間可以共享資源。
- 相比進(jìn)程而言,創(chuàng)建線程代價(jià)比較小。
?3.2、缺點(diǎn)
- 等候使用共享資源時(shí)造成程序的運(yùn)行速度變慢。這些共享資源主要是獨(dú)占性的資源 ,如打印機(jī)等。
- 對(duì)線程進(jìn)行管理要求額外的 CPU開(kāi)銷,線程的使用會(huì)給系統(tǒng)帶來(lái)上下文切換的額外負(fù)擔(dān)
- 可能會(huì)出現(xiàn)線程的死鎖。即對(duì)共享資源加鎖實(shí)現(xiàn)同步的過(guò)程中可能會(huì)死鎖。
?4、java中的多線程
????????在java語(yǔ)言中:?線程A和線程B,堆內(nèi)存和方法區(qū)內(nèi)存共享。?但是棧內(nèi)存獨(dú)立,一個(gè)線程一個(gè)棧。假設(shè)啟動(dòng)10個(gè)線程,會(huì)有10個(gè)棧空間,每個(gè)棧和每個(gè)棧之間,互不干擾,各自執(zhí)行各自的,這就是多線程并發(fā)。
5.、java多線程的聲明周期
?
- 創(chuàng)建(New):線程對(duì)象通過(guò) new 關(guān)鍵字創(chuàng)建,但還未調(diào)用 start() 方法時(shí),線程處于新建狀態(tài)。此時(shí),線程對(duì)象已經(jīng)分配了內(nèi)存空間,但尚未啟動(dòng)執(zhí)行。
- 就緒(Runnable):線程對(duì)象調(diào)用 start() 方法后,線程處于就緒狀態(tài)。此時(shí),線程已經(jīng)準(zhǔn)備好執(zhí)行,但還沒(méi)有獲得 CPU 時(shí)間片。多個(gè)線程處于就緒狀態(tài)時(shí),由 Java 虛擬機(jī)的線程調(diào)度器來(lái)決定哪個(gè)線程獲得 CPU 時(shí)間片開(kāi)始執(zhí)行。
- 運(yùn)行(Running):當(dāng)線程獲得 CPU 時(shí)間片開(kāi)始執(zhí)行時(shí),線程處于運(yùn)行狀態(tài)。此時(shí),線程的 run() 方法正在被執(zhí)行。
- 阻塞(Blocked):在特定情況下,線程可能會(huì)被暫時(shí)掛起,進(jìn)入阻塞狀態(tài)。例如,線程調(diào)用了 sleep() 方法、等待 I/O 操作、獲得了某個(gè)對(duì)象的鎖但沒(méi)有獲取到鎖等。當(dāng)阻塞狀態(tài)的條件解除時(shí),線程會(huì)重新進(jìn)入就緒狀態(tài),等待獲取 CPU 時(shí)間片繼續(xù)執(zhí)行。
- 銷毀(Terminated):線程執(zhí)行完 run() 方法后,或者調(diào)用了 stop() 方法,線程將進(jìn)入銷毀狀態(tài)。一旦線程進(jìn)入了銷毀狀態(tài),就無(wú)法再恢復(fù)到其他狀態(tài)。
?6、Java中多線程的實(shí)現(xiàn)方式
6.1、繼承Thread類
- 定義一個(gè)類繼承Thread類,重寫run方法
- 創(chuàng)建調(diào)用線程類的對(duì)象
- 調(diào)用線程對(duì)象的start方法啟動(dòng)線程(啟動(dòng)后會(huì)自動(dòng)執(zhí)行MyThread中重寫的run()方法)
/*** 1、類繼承Thread類**/
public class ThreadTest extends Thread{//必須重寫Thread類中的run方法@Overridepublic void run() {//super.run();for (int i = 0; i <= 5; i++) {System.out.println("子線程:"+i);}}
}public class ThreadMain {public static void main(String[] args) {//2、創(chuàng)建子線程對(duì)象Thread t = new ThreadTest();//3、啟動(dòng)子線程t.start();for (int i = 0; i <= 5; i++) {System.out.println("主線程:"+i);}}
}
PS:
- 該方法編碼簡(jiǎn)單,但使用了繼承,不利于擴(kuò)展。
- 啟動(dòng)線程必須是用start方法,不能用run方法,否知會(huì)變成單線程。
- 不要把主線程任務(wù)放到啟動(dòng)子線程之前,否則會(huì)變成成主線程執(zhí)行完了,才執(zhí)行子線程。
6.2、實(shí)現(xiàn)Runnable接口
- 定義一個(gè)線程任務(wù)類MyRunnable實(shí)現(xiàn)Runnable接口,重寫run方法
- 創(chuàng)建MyRunnable對(duì)象
- 把MyRunnable對(duì)象交給Thread處理??
/*** 1、實(shí)現(xiàn)Runnable接口**/
public class RunnableTest implements Runnable{//重現(xiàn)run方法@Overridepublic void run() {for (int i = 0; i <= 5; i++) {System.out.println("子線程:"+i);}}
}public class RunnableMain {public static void main(String[] args) {/*** 2.創(chuàng)建子線程對(duì)象*/Runnable target = new RunnableTest();/*** 3.把Runnable對(duì)象交給Thread處理*/Thread t = new Thread(target);t.start();for (int i = 0; i < 5; i++) {System.out.println("主線程執(zhí)行輸出" + i);}}
}
PS:實(shí)現(xiàn)接口,可以繼續(xù)繼承或者實(shí)現(xiàn)接口,擴(kuò)展性強(qiáng)
?匿名內(nèi)部類(推薦方法)
public class RunnableMain1 {public static void main(String[] args) {//簡(jiǎn)化方式一Runnable r = new Runnable() {@Overridepublic void run() {for (int i = 0; i <= 5; i++) {System.out.println("子線程1:"+i);}}};new Thread(r).start();//簡(jiǎn)化方式二new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i <= 5; i++) {System.out.println("子線程2:"+i);}}}).start();//簡(jiǎn)化方式三(lambda表達(dá)式)(jdk8以上)new Thread(() -> {for (int i = 0; i <= 5; i++) {System.out.println("子線程3:"+i);}}).start();for (int i = 0; i < 5; i++) {System.out.println("主線程執(zhí)行輸出" + i);}}
}
6.3、實(shí)現(xiàn)Callable接口,通過(guò)FutureTask接口接收返回值(JDK5新增)
- 得到任務(wù)對(duì)象 第一步:定義一個(gè)線程任務(wù)類MyCallable實(shí)現(xiàn)Callable接口,重寫call方法,該方法可以返回結(jié)果 第二步:用Future吧Callable對(duì)象封裝成線程任務(wù)對(duì)象
- 把線程任務(wù)對(duì)象交給Thread處理
- 調(diào)用Thread的start方法啟動(dòng)任務(wù)
- 線程執(zhí)行完畢后,通過(guò)FutureTask的get方法獲得結(jié)果?
/*** 1、定義一個(gè)實(shí)現(xiàn)類,實(shí)現(xiàn)Callable接口,記得聲明結(jié)果的數(shù)據(jù)類型**/
public class CallableTest implements Callable<String> {//2.重寫call方法private int n;public CallableTest(int n) {this.n = n;}@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <= n; i++) {sum += i;}return "子線程執(zhí)行的結(jié)果是" + sum;}
}public class CalableMain {public static void main(String[] args) {//3.創(chuàng)建任務(wù)對(duì)象Callable<String> call1 = new CallableTest(100);/*** 4.把Callable任務(wù)對(duì)象交給FutureTask對(duì)象* FutureTask的作用1:FutureTask實(shí)現(xiàn)了Runnable接口,此時(shí)就可以交給Thread了* FutureTask的作用2:可以在線程執(zhí)行完畢后調(diào)用get方法得到線程執(zhí)行的結(jié)果*///Thread t = new Thread(call); 報(bào)錯(cuò),Thread不能接收call對(duì)象FutureTask<String> f1 = new FutureTask<>(call1);//5.交給線程處理Thread t1 = new Thread(f1);//6.啟動(dòng)線程t1.start();Callable<String> call2 = new CallableTest(200);FutureTask<String> f2 = new FutureTask<>(call2);Thread t2 = new Thread(f2);t2.start();try {String rs1 = f1.get(); //直接調(diào)用call方法,可能還沒(méi)有執(zhí)行完,使用get時(shí)若發(fā)現(xiàn)線程未執(zhí)行完會(huì)先等線程執(zhí)行完畢System.out.println("第一個(gè)結(jié)果為:" + rs1);} catch (Exception e) {e.printStackTrace();}try {String rs2 = f2.get(); //直接調(diào)用call方法,可能還沒(méi)有執(zhí)行完,使用get時(shí)若發(fā)現(xiàn)線程未執(zhí)行完會(huì)先等線程執(zhí)行完畢System.out.println("第二個(gè)結(jié)果為:" + rs2);} catch (Exception e) {e.printStackTrace();}}
}
PS:
- 擴(kuò)展性強(qiáng),可以繼續(xù)繼承和實(shí)現(xiàn)。
- 可以在線程執(zhí)行完畢后獲取線程執(zhí)行的結(jié)果。
6.4、Thread常用方法和構(gòu)造器
Thread提供的常用方法 | 說(shuō)明 |
public void run() | 線程的任務(wù)方法 |
public void start() | 啟動(dòng)線程 |
jublic String getName() | 獲取當(dāng)前線程的名稱,線程名稱默認(rèn)是Thread-索引 |
public void setName(String name) | 為線程設(shè)置名稱 |
public static Thread currentThread() | 獲取當(dāng)前執(zhí)行的線程對(duì)象 |
public static void sleep(long time) | 讓當(dāng)前執(zhí)行的線程休眠多少毫秒后,再繼續(xù)執(zhí)行 |
public final void join()... | 讓調(diào)用當(dāng)前這個(gè)放的線程先執(zhí)行完 |
Thread提供的常見(jiàn)構(gòu)造器 | 說(shuō)明 |
public Thread(String name) | 可以為當(dāng)前線程指定名稱 |
public Thread(Runnable target) | 封裝Runnable對(duì)象成為線程對(duì)象 |
public Thread(Runnable target,String name) | 封裝Runnable對(duì)象成為線程對(duì)象,并指定線程名稱 |