欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java多線程之JUC(java.util.concurrent)的常見類(多線程編程常用類)

 更新時(shí)間:2024年02月03日 11:31:38   作者:灰灰快醒醒  
這篇文章主要給大家介紹了關(guān)于Java多線程之JUC(java.util.concurrent)的常見類(多線程編程常用類)的相關(guān)資料,Java中的JUC(java.util.concurrent)包提供了一些并發(fā)編程中常用的類,這些類可以幫助我們更方便地實(shí)現(xiàn)多線程編程,需要的朋友可以參考下

Callable接口

這個(gè)東西可以類比于之前見過的Runnable接口.兩者的區(qū)別在于Runnable關(guān)注執(zhí)行過程,不關(guān)注執(zhí)行結(jié)果.Callable關(guān)注執(zhí)行結(jié)果,它之中的call方法(類比于run方法)返回值就是線程執(zhí)行任務(wù)的結(jié)果.Callable<V>里面的V期望線程的入口方法里,返回值是啥類型,此處的泛型參數(shù)就是啥類型.

Callable優(yōu)勢

示例:創(chuàng)建線程計(jì)算1+2+...+1000,使用Runnable版本

public class ThreadDemo7 {
    private static int sum = 0;

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                int result = 0;
                for(int i = 0; i <= 1000; i++) {
                    result += i;
                }
                sum = result;
            }
        });
        t.start();
        t.join();

        //主線程獲取到計(jì)算結(jié)果
        //此處要想獲取到結(jié)果,就需要專門搞一個(gè)成員變量保存上述的計(jì)算結(jié)果
        System.out.println("sum =" + sum);
    }
}

這么做雖然能夠解決問題,但是代碼不是很優(yōu)雅,這時(shí)我們就希望依靠返回值來直接保存計(jì)算結(jié)果,

這就用到了Callable接口,使用流程如下:

 1.創(chuàng)建一個(gè)匿名內(nèi)部類,實(shí)現(xiàn)Callable接口.Callable帶有泛型參數(shù).泛型參數(shù)表示返回值的類型

2.重寫Callable的call方法,完成累加的過程,直接通過返回值返回計(jì)算結(jié)果

3.把callable示例用FutureTask包裝一下.

4.創(chuàng)建線程,線程的構(gòu)造方法傳入FutureTask.此時(shí)新線程就會執(zhí)行FutureTask內(nèi)部的Callable的call方法,完成計(jì)算.計(jì)算結(jié)果就放進(jìn)了FutureTask對象中.

5.在主線程中調(diào)用futureTask.get()能夠阻塞等待新線程計(jì)算完畢.并獲取FutureTask中的結(jié)果.

代碼如下:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadDemo8 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int result = 0;
                for(int i = 0; i <= 1000; i++) {
                    result += i;
                }
                return result;
            }
        };

        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();

        //接下來這個(gè)代碼也不需要join,使用futureTask獲取到結(jié)果.
        //get()方法具有阻塞功能.如果線程不執(zhí)行完畢,get就會阻塞
        //等到線程執(zhí)行完了,return的結(jié)果,就會被get返回回來
        System.out.println(futureTask.get());
    }
}

可以看到,使用Callable和FutureTask之后,代碼簡化了很多,也不必手動寫線程同步代碼了.

理解Callable

Callable通常需要搭配FutureTask來使用.FutureTask用來保存Callable的返回結(jié)果.因?yàn)镃allable往往是在另一個(gè)線程中執(zhí)行的,什么時(shí)候執(zhí)行完并不確定. 

FutureTask就可以負(fù)責(zé)這個(gè)等待結(jié)果出來的工作.

理解FutureTask

FutureTask即未來的任務(wù),既然這個(gè)任務(wù)是在未來執(zhí)行完畢,最終取結(jié)果時(shí)就需要一張憑證.

可以想象成去吃麻辣燙.當(dāng)餐點(diǎn)好后,后廚就開始做了.同時(shí)前臺會給你一張小票.這個(gè)小票就是FutureTask.后面我們可以隨時(shí)憑這張小票去查看自己的這份麻辣燙做出來沒.

總結(jié):創(chuàng)建線程的方式:1.繼承Thread(包含匿名內(nèi)部類).2.實(shí)現(xiàn)Runnable(包含匿名內(nèi)部類).

3.基于lambda. 4.基于Callable. 5.基于線程池.

ReentrantLock

可重入互斥鎖.和synchronized定位類似,都是用來實(shí)現(xiàn)互斥效果,保證線程安全.

ReentrantLock也是可重入鎖."Reentrant"這個(gè)單詞的原意就是"可重入".

ReentrantLock的用法:

lock():加鎖,如果獲取不到鎖就死等.

trylock(超時(shí)時(shí)間):加鎖,如果獲取不到鎖,等待一定時(shí)間之后就放棄加鎖.(此處通過trylock提供了更多的可操作空間)

unlock():解鎖

ReentrantLock lock = new ReentrantLock();
-----------------------------------------

lock.lock();
try {
    //working...
} finally {
    lock.unlock()
}

 ReentrantLock和synchronized的區(qū)別

通過上述解釋,我們不免發(fā)現(xiàn)ReentrantLock和Synchronized非常相像,下面來說一說他們的區(qū)別:

1.synchronized是一個(gè)關(guān)鍵字,是JVM內(nèi)部實(shí)現(xiàn)的(大概率是基于C++實(shí)現(xiàn)).ReentrantLock是標(biāo)準(zhǔn)庫中的一個(gè)類,在JVM外實(shí)現(xiàn)的(基于Java實(shí)現(xiàn)).

2.synchronized使用時(shí)不需要手動釋放鎖.ReentrantLock使用時(shí)需要手動釋放.使用起來更靈活,但是也容易遺漏unlock.

3.synchronized在申請失敗時(shí),會死等.ReentrantLock可以通過trylock的方式等待一段時(shí)間后就放棄

4.synchronized是非公平鎖,ReentrantLock默認(rèn)是非公平鎖.可以通過一個(gè)構(gòu)造方法傳入一個(gè)true進(jìn)入公平鎖模式(原理:通過隊(duì)列記錄加鎖線程的先后順序).

//ReentrantLock的構(gòu)造方法
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

5.搭配的等待通知機(jī)制是不同的

對于synchronize,搭配wait/notify

對于ReentrantLock,搭配Condition類,功能比wait,notify略強(qiáng)一些.

如何選擇使用哪個(gè)鎖

1.鎖競爭不激烈時(shí),使用synchronized,效率更高,自動釋放更方便.

2.鎖競爭激烈時(shí),搭配trylock更靈活控制鎖的行為,而不是死等

3.如果需要使用公平鎖,使用ReentrantLock.

其實(shí),一般情況下會使用synchronized即可.

信號量Semaphore

信號量,用來表示"可用資源的個(gè)數(shù)".本質(zhì)上就是一個(gè)計(jì)數(shù)器.

理解信號量(想象成一個(gè)更廣義的鎖)

可以把信號量想象成是停車場的展示牌:當(dāng)前有車位100個(gè).表示有100個(gè)可用資源.

當(dāng)有車開進(jìn)去的時(shí)候,就相當(dāng)于申請(acquire)一個(gè)可用資源,可用車位就-1.(這稱為信號量的P操作)

當(dāng)有車開出來的時(shí)候,就相當(dāng)于釋放(release)一個(gè)可用資源,可用車位就+1.(這稱為信號量的V操作)

如果計(jì)數(shù)器的值已經(jīng)為0了,還嘗試申請資源,就會堵塞等待,直到有其它線程釋放資源.

Semaphore的PV操作中的加減計(jì)數(shù)器操作都是原子的,可以在多線程下直接使用.

所謂鎖本質(zhì)也是一種特殊的信號量.鎖可以認(rèn)為就是計(jì)數(shù)值為1的信號量,釋放狀態(tài)就是1,加鎖狀態(tài)就是0.對于這種非0即1的信號量.稱為"二元信號量".

代碼示例:

1.創(chuàng)建Semaphore示例,初始化為4,表示有4個(gè)可用資源.

2.acquire方法表示申請資源(P操作),release方法表示釋放資源(V操作).

3.創(chuàng)建20個(gè)線程,每個(gè)線程都嘗試申請資源,sleep一秒之后,釋放資源,觀察程序的執(zhí)行效果.

import java.util.concurrent.Semaphore;

public class ThreadDemo9 {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(4);

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("申請資源");
                    semaphore.acquire();
                    System.out.println("我獲取到資源了");
                    Thread.sleep(1000);
                    System.out.println("我釋放資源了");
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        for(int i = 0; i < 10; i++) {
            Thread t = new Thread(runnable);
            t.start();
        }
    }
}

總結(jié):如何保證線程安全

1.synchronized

2.Reentrantlock

3.CAS(原子類)

4.Semaphore (也可以用于實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型:

定義兩個(gè)信號量:一個(gè)用來表示隊(duì)列中有多少個(gè)可以消費(fèi)的元素sem1,另一個(gè)用于表示隊(duì)列中有多少個(gè)可放置新元素的空間sem2.

生產(chǎn):sem1.V(),sem2.P()

消費(fèi):sem1.P(),sem2.V()

CountDownLatch

同時(shí)等待N個(gè)任務(wù)執(zhí)行結(jié)束.(多線程中執(zhí)行一個(gè)任務(wù),把大的任務(wù)分為幾個(gè)部分,由每個(gè)線程分別執(zhí)行).

就好像跑步比賽,10個(gè)選手依次就位,哨聲響了才能同時(shí)出發(fā);所有選手都通過終點(diǎn),才能公布成績.

1.構(gòu)造CountDownLatch實(shí)例,初始化10表示有10個(gè)任務(wù)需要完成.

2.每個(gè)任務(wù)執(zhí)行完畢,都調(diào)用latch.countDown().在CountDownLatch1內(nèi)部的計(jì)數(shù)器同時(shí)自減

3.主線程中使用latch.await();阻塞等待所有任務(wù)執(zhí)行完畢.相當(dāng)于計(jì)數(shù)器為0了.

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class ThreadDemo10 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(10);
        Runnable r = new Runnable() {
            @Override
            public void run() {
                Random random = new Random();
                int x = random.nextInt(5) + 1;
                try {
                    Thread.sleep(x * 1000);
                    latch.countDown();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };

        for(int i = 0; i < 10; i++) {
            new Thread(r).start();
        }

        //必須等到所有線程全部結(jié)束
        latch.await();
        System.out.println("比賽結(jié)束");
    }
}

相關(guān)面試題

1.線程同步的方式有哪些?

synchronized, ReentrantLock, Semaphore等都用于線程同步.

2.為什么有了synchronized還需要juc下的lock?

以juc的ReentrantLock為例,

synchronized使用時(shí)不需要手動釋放鎖.ReentrantLock使用時(shí)需要通過手動釋放,使用起來更加靈活.

synchronized在申請失敗后會死等.ReentrantLock可以通過trylock的方式等待一段時(shí)間就放棄.

synchronized是非公平鎖,ReentrantLock默認(rèn)是非公平鎖.可以通過構(gòu)造方法傳入一個(gè)true開啟公平鎖模式

synchronized是通過Object的wait/notify實(shí)現(xiàn)等待-喚醒.每次喚醒的是一個(gè)隨機(jī)等待的線程.ReentrantLock搭配Condition類實(shí)現(xiàn)等待-喚醒,可以更精確的控制喚醒某個(gè)指定的線程.

3.信號量聽說過嗎?都用于哪些場景下?

信號量,用來表示"可用資源的個(gè)數(shù)",本質(zhì)上就是一個(gè)計(jì)數(shù)器.

使用信號量可以實(shí)現(xiàn)"共享鎖",比如某個(gè)資源允許3個(gè)線程同時(shí)使用,那么就可以使用P操作加鎖,V操作為解鎖,前三個(gè)線程的P操作都能順利返回,后續(xù)再進(jìn)行P操作就會阻塞等待,直到前面的線程執(zhí)行了V操作.

總結(jié) 

到此這篇關(guān)于Java多線程之JUC(java.util.concurrent)的常見類(多線程編程常用類)的文章就介紹到這了,更多相關(guān)Java JUC常見類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)八個(gè)常用的排序算法:插入排序、冒泡排序、選擇排序、希爾排序等

    Java實(shí)現(xiàn)八個(gè)常用的排序算法:插入排序、冒泡排序、選擇排序、希爾排序等

    這篇文章主要介紹了Java如何實(shí)現(xiàn)八個(gè)常用的排序算法:插入排序、冒泡排序、選擇排序、希爾排序 、快速排序、歸并排序、堆排序和LST基數(shù)排序,需要的朋友可以參考下
    2015-07-07
  • 一文講透為什么遍歷LinkedList要用增強(qiáng)型for循環(huán)

    一文講透為什么遍歷LinkedList要用增強(qiáng)型for循環(huán)

    這篇文章主要為大家介紹了為什么遍歷LinkedList要用增強(qiáng)型for循環(huán)的透徹詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Java中的事件處理機(jī)制詳解

    Java中的事件處理機(jī)制詳解

    這篇文章主要介紹了Java中的事件處理機(jī)制詳解,Java事件處理是采取"委派事件模型",當(dāng)事件發(fā)生時(shí),產(chǎn)生事件的對象,會把此"信息"傳遞給"事件的監(jiān)聽者"處理,這里所說的"信息"實(shí)際上就是java.awt.event事件類庫里某個(gè)類創(chuàng)建對象,把它稱為"事件的對象",需要的朋友可以參考下
    2023-10-10
  • pageHelper一對多分頁解決方案示例

    pageHelper一對多分頁解決方案示例

    這篇文章主要為大家介紹了pageHelper一對多分頁解決方案示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • Java反射機(jī)制的實(shí)現(xiàn)詳解

    Java反射機(jī)制的實(shí)現(xiàn)詳解

    反射主要解決動態(tài)編程,即使用反射時(shí),所有的對象生成是動態(tài)的,因此調(diào)用的方法也是動態(tài)的.反射可以簡化開發(fā),但是代碼的可讀性很低
    2013-05-05
  • Java中Process類的使用與注意事項(xiàng)說明

    Java中Process類的使用與注意事項(xiàng)說明

    這篇文章主要介紹了Java中Process類的使用與注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • spring如何集成cxf實(shí)現(xiàn)webservice接口功能詳解

    spring如何集成cxf實(shí)現(xiàn)webservice接口功能詳解

    這篇文章主要給大家介紹了關(guān)于spring如何集成cxf實(shí)現(xiàn)webservice接口功能的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家 的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧
    2018-07-07
  • 淺談maven 多環(huán)境打包發(fā)布的兩種方式

    淺談maven 多環(huán)境打包發(fā)布的兩種方式

    這篇文章主要介紹了淺談maven 多環(huán)境打包發(fā)布的兩種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法

    Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法

    和MyBatis類似,Spring或者Spring MVC框架在Web應(yīng)用程序的運(yùn)作中同樣主要負(fù)責(zé)處理數(shù)據(jù)庫事務(wù),這里我們就來看一下Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法
    2016-06-06
  • Java中null的意義及其使用時(shí)的注意事項(xiàng)說明

    Java中null的意義及其使用時(shí)的注意事項(xiàng)說明

    這篇文章主要介紹了Java中null的意義及其使用時(shí)的注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09

最新評論