java多線程學(xué)習(xí)筆記

前言:對于java多線程的資料數(shù)不勝數(shù),我們這里只是在學(xué)習(xí)后簡單地總結(jié)一下并給出一些小例子,本文適合java初學(xué)者。不過在開始之前,我們還是要弄明白一個問題——線程和進程有什么區(qū)別?其實一個進程是一個獨立的運行環(huán)境,它可以被看作一個程序或者一個應(yīng)用,而線程是在進程中執(zhí)行的一個任務(wù),線程是進程的子集,一個進程可以有很多線程,每條線程并行執(zhí)行不同的任務(wù)。不同的進程使用不同的內(nèi)存空間,而所有的線程共享一片相同的內(nèi)存空間。別把它和棧內(nèi)存搞混,每個線程都擁有單獨的棧內(nèi)存用來存儲本地數(shù)據(jù)。

1.創(chuàng)建線程的方法

創(chuàng)建線程方法一:繼承Thread類,使用子類創(chuàng)建

編寫繼承Thread子類MyThread

//MyThread.java

public class MyThread extends Thread{

? ?private String name;

? ?public MyThread(String name){

? ? ? this.name= name;

? ?}

? ?//繼承Thread類必須重寫run()方法

? ?@Override

? ?public void run() {

? ? ? System.out.println("name:" + name + "子線程ID:"

? ? ? + Thread.currentThread().getId());

? ?}

}

在main方法里面編寫代碼:

System.out.println("主線程ID:"+ Thread.currentThread().getId());

//創(chuàng)建多個子線程

for(int i = 0; i < 5; i++){

? ?String threadName = "Thread" + (i + 1);

? ?MyThread thread = new MyThread(threadName);

? ?thread.start();

}

//注:直接調(diào)用Thread的run方法,并不會在新的線程上執(zhí)行,而是跟普通方法調(diào)用一樣,在當(dāng)前線程上執(zhí)行

MyThread threadSpec = new MyThread("ThreadSpec"); ? //特例

threadSpec.run();

運行結(jié)果

說明:啟動線程是通過start()方法,而不是調(diào)用run()方法,在線程獲取cpu執(zhí)行時間的時候會自動調(diào)用run()方法。

創(chuàng)建線程方法二:實現(xiàn)Runnable接口,在Runnable上定義任務(wù),然后將Runnable交由Thread執(zhí)行

編寫實現(xiàn)Runnable的實現(xiàn)類MyRunnable

//MyRunnable.java

public class MyRunnable implements Runnable {

? ?public MyRunnable(){}

? ?//實現(xiàn)Runnable接口必須重寫其run方法

? ?@Override

? ?public void run() {

? ? ? System.out.println("子線程ID:"+ Thread.currentThread().getId());

? ?}

}

在main方法里面編寫代碼:

MyRunnable runnable = new MyRunnable();

Thread thread = new Thread(runnable);

thread.start();

運行結(jié)果

說明:和方法一對比,方法二可能有些啰嗦,但是Java只允許單繼承,如果實際情況中類需要繼承其他類,則只能選擇方法二來實現(xiàn)多線程。

2.使用ExecutorService、Callable、Future實現(xiàn)有返回結(jié)果的多線程

先編寫實現(xiàn)Callable的實現(xiàn)類MyCallable

//MyCallable.java

public class MyCallable implements Callable {

? ?private String taskIndex;

? ?MyCallable(String taskIndex){

? ? ? this.taskIndex = taskIndex;

}

? ?@Override

? ?public Object call() throws Exception {

? ? ? System.out.println(taskIndex + "號任務(wù)啟動");

? ? ? Date startDate = new Date();

? ? ? Thread.sleep(1000);

? ? ? Date endDate = new Date();

? ? ? long time = endDate.getTime() - startDate.getTime();

? ? ? System.out.println(taskIndex + "號任務(wù)終止");

? ? ? return taskIndex + "號任務(wù)返回運行結(jié)果,當(dāng)前任務(wù)執(zhí)行【" + time +"毫秒】";

? ?}

}

在main方法里面編寫代碼:

//使用ExecutorService、Callable、Future實現(xiàn)有返回結(jié)果的多線程

System.out.println("------程序開始運行-----");

Date startDate = new Date();

int taskSize = 5;

//創(chuàng)建一個線程池

ExecutorService pool = Executors.newFixedThreadPool(taskSize);

//創(chuàng)建多個有返回值的任務(wù)

List list =new ArrayList<>();

for(int i =0;i < taskSize;i++){

? ?Callable c = new MyCallable(i +"");

? ?//執(zhí)行任務(wù)并獲取Future對象

? ?Future f = pool.submit(c);

? ?list.add(f);

}

//關(guān)閉線程池

pool.shutdown();

//獲取所有并發(fā)任務(wù)的運行結(jié)果

for(Future f : list){

? ?//從Future對象上獲取任務(wù)的返回值

? ?System.out.println(f.get().toString());

}

Date endDate =new Date();

System.out.println("------程序結(jié)束運行-----,程序運行了【"+ (endDate.getTime() - startDate.getTime()) +"毫秒】");

運行結(jié)果

說明:ExecutorService、Callable、Future這個對象實際上都是屬于Executor框架中的功能類。想要詳細了解Executor框架的可以訪問Java程序員必備知識-多線程框架Executor詳解。實現(xiàn)Callable接口,執(zhí)行Callable任務(wù)后,可以獲取一個Future的對象,在該對象上調(diào)用get就可以獲取到Callable任務(wù)返回的Object了。

注:以上內(nèi)容是學(xué)習(xí)java 多線程后的一個簡單的總結(jié),如果有錯誤,請各位指出,也歡迎大家前來拍磚,灰常感謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容