溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么實(shí)現(xiàn)Java多線程并發(fā)

發(fā)布時(shí)間:2021-11-01 10:21:35 來(lái)源:億速云 閱讀:260 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“怎么實(shí)現(xiàn)Java多線程并發(fā)”,在日常操作中,相信很多人在怎么實(shí)現(xiàn)Java多線程并發(fā)問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么實(shí)現(xiàn)Java多線程并發(fā)”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

  繼承 Thread 類(lèi)

  Thread 類(lèi)本質(zhì)上是實(shí)現(xiàn)了 Runnable 接口的一個(gè)實(shí)例,代表一個(gè)線程的實(shí)例。啟動(dòng)線程的唯一方法就是通過(guò) Thread 類(lèi)的 start()實(shí)例方法。start()方法是一個(gè) native 方法,它將啟動(dòng)一個(gè)新線程,并執(zhí)行 run()方法。

public class MyThread extends Thread {

public void run() {

System.out.println("MyThread.run()");

} }

MyThread myThread1 = new MyThread();

myThread1.start();

實(shí)現(xiàn) Runnable 接口

如果自己的類(lèi)已經(jīng) extends 另一個(gè)類(lèi),就無(wú)法直接 extends Thread,此時(shí),可以實(shí)現(xiàn)一個(gè)Runnable 接口。

public class MyThread extends OtherClass implements Runnable {

public void run() {

System.out.println("MyThread.run()");

} } //啟動(dòng)

MyThreadMyThread myThread = new MyThread();

Thread thread = new Thread(myThread);

thread.start();

target.run()public void run() {

if (target != null) {

target.run();

} }

ExecutorService、Callable、Future 有返回值線程

有返回值的任務(wù)必須實(shí)現(xiàn) Callable 接口,類(lèi)似的,無(wú)返回值的任務(wù)必須 Runnable 接口。執(zhí)行Callable 任務(wù)后,可以獲取一個(gè) Future 的對(duì)象,在該對(duì)象上調(diào)用 get 就可以獲取到 Callable 任務(wù)返回的 Object 了,再結(jié)合線程池接口 ExecutorService 就可以實(shí)現(xiàn)傳說(shuō)中有返回結(jié)果的多線程了。

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

ExecutorService pool = Executors.newFixedThreadPool(taskSize);

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

List<Future> list = new ArrayList<Future>();

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

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

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

Future f = pool.submit(c); list.add(f);

} // 關(guān)閉線程池pool.shutdown();

// 獲取所有并發(fā)任務(wù)的運(yùn)行結(jié)果for (Future f : list) {

// 從 Future 對(duì)象上獲取任務(wù)的返回值,并輸出到控制臺(tái)System.out.println("res:" + f.get().toString());

}

基于線程池的方式

線程和數(shù)據(jù)庫(kù)連接這些資源都是非常寶貴的資源。如果每次需要的時(shí)候創(chuàng)建,不需要的時(shí)候銷(xiāo)毀,是非常浪費(fèi)資源的。那么我們就可以使用緩存的策略,也就是使用線程池。

// 創(chuàng)建線程池ExecutorService threadPool = Executors.newFixedThreadPool(10);

while(true) { threadPool.execute(new Runnable() {

// 提交多個(gè)線程執(zhí)行 @Override public void run() {

System.out.println(Thread.currentThread().getName() + " is running ..");

try {

Thread.sleep(3000);

}

catch (InterruptedException e) {

e.printStackTrace();

} } }); }}

2 同步鎖與死鎖

同步鎖當(dāng)多個(gè)線程同時(shí)訪問(wèn)同一個(gè)數(shù)據(jù)時(shí),很容易出現(xiàn)問(wèn)題。為了避免這種情況出現(xiàn),我們要保證線程同步互斥,就是指并發(fā)執(zhí)行的多個(gè)線程,在同一時(shí)間內(nèi)只允許一個(gè)線程訪問(wèn)共享數(shù)據(jù)。Java中可以使用synchronized關(guān)鍵字來(lái)取得一個(gè)對(duì)象的同步鎖。

死鎖何為死鎖,就是多個(gè)線程同時(shí)被阻塞,它們中的一個(gè)或者全部都在等待某個(gè)資源被釋放。

3 線程池原理

線程池做的工作主要是控制運(yùn)行的線程的數(shù)量,處理過(guò)程中將任務(wù)放入隊(duì)列,然后在線程創(chuàng)建后啟動(dòng)這些任務(wù),如果線程數(shù)量超過(guò)了最大數(shù)量超出數(shù)量的線程排隊(duì)等候,等其它線程執(zhí)行完畢,再?gòu)年?duì)列中取出任務(wù)來(lái)執(zhí)行。主要特點(diǎn)為:線程復(fù)用;控制最大并發(fā)數(shù);管理線程。

線程復(fù)用一個(gè)Thread的類(lèi)都有一個(gè)start方法。當(dāng)調(diào)用start啟動(dòng)線程時(shí)Java虛擬機(jī)會(huì)調(diào)用該類(lèi)的 run 方法。那么該類(lèi)的 run() 方法中就是調(diào)用了 Runnable 對(duì)象的 run() 方法。我們可以繼承重寫(xiě) Thread 類(lèi),在其 start 方法中添加不斷循環(huán)調(diào)用傳遞過(guò)來(lái)的 Runnable 對(duì)象。這就是線程池的實(shí)現(xiàn)原理。循環(huán)方法中不斷獲取 Runnable 是用 Queue 實(shí)現(xiàn)的,在獲取下一個(gè) Runnable 之前可以是阻塞的。

線程池的組成一般的線程池主要分為以下 4 個(gè)組成部分:

(1)線程池管理器:用于創(chuàng)建并管理線程池。(2)工作線程:線程池中的線程。(3)任務(wù)接口:每個(gè)任務(wù)必須實(shí)現(xiàn)的接口,用于工作線程調(diào)度其運(yùn)行。(4)任務(wù)隊(duì)列:用于存放待處理的任務(wù),提供一種緩沖機(jī)制。

Java 中的線程池是通過(guò) Executor 框架實(shí)現(xiàn)的,該框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor ,Callable 和 Future、FutureTask 這幾個(gè)類(lèi)。

ThreadPoolExecutor 的構(gòu)造方法如下:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}

corePoolSize:指定了線程池中的線程數(shù)量。

maximumPoolSize:指定了線程池中的最大線程數(shù)量。

keepAliveTime:當(dāng)前線程池?cái)?shù)量超過(guò) corePoolSize 時(shí),多余的空閑線程的存活時(shí)間,即多次時(shí)間內(nèi)會(huì)被銷(xiāo)毀。

unit:keepAliveTime 的單位。

workQueue:任務(wù)隊(duì)列,被提交但尚未被執(zhí)行的任務(wù)。

threadFactory:線程工廠,用于創(chuàng)建線程,一般用默認(rèn)的即可。

handler:拒絕策略,當(dāng)任務(wù)太多來(lái)不及處理,如何拒絕任務(wù)。

拒絕策略線程池中的線程已經(jīng)用完了,無(wú)法繼續(xù)為新任務(wù)服務(wù),同時(shí),等待隊(duì)列也已經(jīng)排滿了,再也塞不下新任務(wù)了。這時(shí)候我們就需要拒絕策略機(jī)制合理的處理這個(gè)問(wèn)題。

JDK 內(nèi)置的拒絕策略如下:

AbortPolicy :直接拋出異常,阻止系統(tǒng)正常運(yùn)行。

CallerRunsPolicy :只要線程池未關(guān)閉,該策略直接在調(diào)用者線程中,運(yùn)行當(dāng)前被丟棄的任務(wù)。顯然這樣做不會(huì)真的丟棄任務(wù),但是,任務(wù)提交線程的性能極有可能會(huì)急劇下降。

DiscardOldestPolicy :丟棄最老的一個(gè)請(qǐng)求,也就是即將被執(zhí)行的一個(gè)任務(wù),并嘗試再次提交當(dāng)前任務(wù)。

DiscardPolicy :該策略默默地丟棄無(wú)法處理的任務(wù),不予任何處理。如果允許任務(wù)丟失,這是最好的一種方案。

以上內(nèi)置拒絕策略均實(shí)現(xiàn)了 RejectedExecutionHandler 接口,若以上策略仍無(wú)法滿足實(shí)際需要,完全可以自己擴(kuò)展 RejectedExecutionHandler 接口。

Java 線程池工作過(guò)程(1)線程池剛創(chuàng)建時(shí),里面沒(méi)有一個(gè)線程。任務(wù)隊(duì)列是作為參數(shù)傳進(jìn)來(lái)的。不過(guò),就算隊(duì)列里面有任務(wù),線程池也不會(huì)馬上執(zhí)行它們。

(2)當(dāng)調(diào)用 execute() 方法添加一個(gè)任務(wù)時(shí),線程池會(huì)做如下判斷:

a) 如果正在運(yùn)行的線程數(shù)量小于 corePoolSize,那么馬上創(chuàng)建線程運(yùn)行這個(gè)任務(wù);

b) 如果正在運(yùn)行的線程數(shù)量大于或等于 corePoolSize,那么將這個(gè)任務(wù)放入隊(duì)列;

c) 如果這時(shí)候隊(duì)列滿了,而且正在運(yùn)行的線程數(shù)量小maximumPoolSize,那么還是要?jiǎng)?chuàng)建非核心線程立刻運(yùn)行這個(gè)任務(wù);

d) 如果隊(duì)列滿了,而且正在運(yùn)行的線程數(shù)量大于或等maximumPoolSize,那么線程池會(huì)拋出異常 RejectExecutionException。

(3)當(dāng)一個(gè)線程完成任務(wù)時(shí),它會(huì)從隊(duì)列中取下一個(gè)任務(wù)來(lái)執(zhí)行。

(4)當(dāng)一個(gè)線程無(wú)事可做,超過(guò)一定的時(shí)間(keepAliveTime)時(shí),線程池會(huì)判斷,如果當(dāng)前運(yùn)行的線程數(shù)大于 corePoolSize,那么這個(gè)線程就被停掉。所以線程池的所有任務(wù)完成后,它最終會(huì)收縮到 corePoolSize 的大小。

到此,關(guān)于“怎么實(shí)現(xiàn)Java多線程并發(fā)”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI