多線程同步控制使用示例

背景

在公司做某個(gè)項(xiàng)目的時(shí)候女器,所有數(shù)據(jù)從第三方通過調(diào)用接口的方式獲取到。但是第三方返回的數(shù)據(jù)有新老數(shù)據(jù)之分栗竖,所謂新老數(shù)據(jù)之分,是指某一條數(shù)據(jù)渠啤,你對(duì)它進(jìn)行了修改狐肢,數(shù)據(jù)庫會(huì)存兩條,舊的一條估計(jì)是作為歷史版本數(shù)據(jù)沥曹。但是份名,第三方返給我的數(shù)據(jù)是沒有一個(gè)字段去標(biāo)識(shí)這個(gè)新舊數(shù)據(jù)的碟联。所以,這就需要去做個(gè)過濾僵腺。為了簡(jiǎn)便鲤孵,在獲取到所有數(shù)據(jù)之后,把新數(shù)據(jù)單獨(dú)存表辰如,后面的操作以這個(gè)表為主表普监,就可以避免很多麻煩∩ッ唬可能很多人看完這個(gè)第一感覺會(huì)把這個(gè)問題歸于去重鹰椒。后面我否定了,我認(rèn)為去重呕童,是指數(shù)據(jù)存在多條一模一樣的漆际,去掉重復(fù)的,隨便取一條夺饲,或者我認(rèn)為這個(gè)比去重稍稍復(fù)雜一點(diǎn)奸汇。(條條大路通羅馬,不一定非得最優(yōu)解嘛往声,視圖就不說了)

正題

第三方提供的接口很多擂找,為了提高效率,采用多線程的方式去拉去數(shù)據(jù)浩销。那么問題來了贯涎,一次同時(shí)跑多少個(gè)線程?越多越好嗎?答案肯定是否定的。至于具體多少個(gè)慢洋,網(wǎng)上給出了答案塘雳。我個(gè)人沒有測(cè)試,有興趣你們可以試試普筹。
拿來主義之網(wǎng)上說-最好起cpu核心數(shù)量x2個(gè)線程或者 cpu核心數(shù)量x2+2個(gè)線程败明。

重新扯回正題:如何實(shí)現(xiàn)先把所有數(shù)據(jù)拉取完了之后,在單獨(dú)起一個(gè)線程去做數(shù)據(jù)收集太防?
這就需要對(duì)線程做一些控制了妻顶。網(wǎng)上給出了幾種方案,我選擇了使用CountDownLatch線程輔助同步類蜒车。

示例代碼

這是主測(cè)試代碼讳嘱,功能就是創(chuàng)建一個(gè)固定大小為5的線程池。用線程池去跑11線程酿愧。這里面主要是要注意設(shè)置需要等待線程的數(shù)量呢燥。CountDownLatch countDownLatch = new CountDownLatch(10);這個(gè)表示線程記數(shù)為10個(gè)寓娩。


import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Mian {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        List<Runnable> taskList = new ArrayList<Runnable>();
        CountDownLatch countDownLatch = new CountDownLatch(10);//這個(gè)是重點(diǎn)
        taskList.add(new Special(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.add(new Common(countDownLatch));
        taskList.forEach(t -> {
            executorService.execute(t);
        });
        executorService.shutdown();
    }
}

下面是普通的線程代碼叛氨,這個(gè)里面需要注意的就是countDownLatch.countDown()這句話呼渣,把線程記數(shù)值減一。這步操作也是加鎖的寞埠,因?yàn)橛洈?shù)對(duì)于所有線程來說都是共享的屁置,多線程操作共享變量,你懂得不加鎖會(huì)怎樣仁连。

package thread;

import java.util.concurrent.CountDownLatch;

public class Common implements Runnable {

    private CountDownLatch countDownLatch;

    public Common(CountDownLatch countDownLatch) {
        this.setCountDownLatch(countDownLatch);
    }

    @Override
    public void run() {
        synchronized (countDownLatch) {
            System.out.println("進(jìn)入普通線程了");
            countDownLatch.countDown();
            System.out.println("目前的線程記數(shù)值為:" + countDownLatch.getCount());
        }
    }

    public CountDownLatch getCountDownLatch() {
        return countDownLatch;
    }

    public void setCountDownLatch(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

}

下面是特定的線程蓝角,它需要等待我前面設(shè)置的線程跑完之后在運(yùn)行。這里面主要的代碼就是countDownLatch.await()饭冬;這句話的就是去判斷線程記數(shù)值是否為0使鹅。若是0就會(huì)繼續(xù)往下走,否則就會(huì)阻塞昌抠。

package thread;

import java.util.concurrent.CountDownLatch;

public class Special implements Runnable {

    private CountDownLatch countDownLatch;

    public Special(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        System.out.println("進(jìn)入特殊線程");
        System.out.println("特殊線程患朱,此時(shí)線程記數(shù)值為:" + countDownLatch.getCount());
        try {
            countDownLatch.await();//這是重點(diǎn)
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("特殊線程,此時(shí)線程記數(shù)值為:" + countDownLatch.getCount());
        System.out.println("特殊線程炊苫,結(jié)束特殊線程");
    }

    public CountDownLatch getCountDownLatch() {
        return countDownLatch;
    }

    public void setCountDownLatch(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

}

運(yùn)行結(jié)果:


運(yùn)行結(jié)果

大家可以看到雖然一開始打印了進(jìn)入特殊線程裁厅,但是卻并未輸出結(jié)束特殊線程,而是最后才執(zhí)行侨艾,說明


說明

當(dāng)運(yùn)行到紅框的時(shí)候执虹,該線程就進(jìn)入了阻塞。直到其他所有線程運(yùn)行完畢唠梨,才重新喚醒它往后執(zhí)行袋励。到這兒可以說是已經(jīng)實(shí)現(xiàn)了我想要的效果。
下面我在截幾張運(yùn)行結(jié)果的圖
結(jié)果一

結(jié)果二

結(jié)果三

細(xì)心的小伙伴可能發(fā)現(xiàn)咋后面的數(shù)字每次都感覺不一樣当叭。線程池嘛插龄,執(zhí)行五個(gè)線程,這五個(gè)線程是有先后的嘛科展。

源碼賞析

countDownLatch.countDown()這個(gè)方法會(huì)把記數(shù)值減一(默認(rèn)的哈),同時(shí)當(dāng)值為零的時(shí)候糠雨,就會(huì)去喚醒出于阻塞的線程才睹。貼哈源碼。


countDown

releaseShared

tryReleaseShared

doReleaseShared

unparkSuccessor

unpark

我個(gè)人理解unpark是真正的喚醒機(jī)制甘邀,這個(gè)是屬于操作系統(tǒng)層面的東西了琅攘。(個(gè)人拙見)

countDownLatch.await()這個(gè)就比較簡(jiǎn)單了,當(dāng)值不為零就阻塞松邪,否則就直接運(yùn)行了坞琴。貼哈源碼


await

acquireSharedInterruptibly

tryAcquireShared

doAcquireSharedInterruptibly

tryAcquireShared判斷是否阻塞,doAcquireSharedInterruptibly阻塞的具體操作(個(gè)人拙見)

結(jié)語

對(duì)多線程的操作呢逗抑,我也是個(gè)菜鳥剧辐,如有錯(cuò)誤之處寒亥,望不吝賜教。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末荧关,一起剝皮案震驚了整個(gè)濱河市溉奕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忍啤,老刑警劉巖加勤,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異同波,居然都是意外死亡鳄梅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門未檩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戴尸,“玉大人,你說我怎么就攤上這事讹挎⌒3啵” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵筒溃,是天一觀的道長(zhǎng)马篮。 經(jīng)常有香客問我,道長(zhǎng)怜奖,這世上最難降的妖魔是什么浑测? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮歪玲,結(jié)果婚禮上迁央,老公的妹妹穿的比我還像新娘。我一直安慰自己滥崩,他們只是感情好岖圈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钙皮,像睡著了一般蜂科。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上短条,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天导匣,我揣著相機(jī)與錄音,去河邊找鬼茸时。 笑死贡定,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的可都。 我是一名探鬼主播缓待,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚓耽,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了命斧?” 一聲冷哼從身側(cè)響起田晚,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎国葬,沒想到半個(gè)月后贤徒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡汇四,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年接奈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片通孽。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡序宦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出背苦,到底是詐尸還是另有隱情互捌,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布行剂,位于F島的核電站秕噪,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏厚宰。R本人自食惡果不足惜腌巾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铲觉。 院中可真熱鬧澈蝙,春花似錦、人聲如沸撵幽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盐杂。三九已至逗载,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間况褪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工更耻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留测垛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓秧均,卻偏偏與公主長(zhǎng)得像食侮,于是被迫代替她去往敵國(guó)和親号涯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 一锯七、多線程 說明下線程的狀態(tài) java中的線程一共有 5 種狀態(tài)链快。 NEW:這種情況指的是,通過 New 關(guān)鍵字創(chuàng)...
    Java旅行者閱讀 4,676評(píng)論 0 44
  • 線程池ThreadPoolExecutor corepoolsize:核心池的大小眉尸,默認(rèn)情況下域蜗,在創(chuàng)建了線程池之后...
    irckwk1閱讀 724評(píng)論 0 0
  • 「公冶長(zhǎng)篇第五」3-4 【原文】 3子謂子賤:“君子哉若人霉祸!魯無君子者,斯焉取斯袱蜡?” 4子貢問曰:“賜也何如丝蹭?”子...
    善氏閱讀 585評(píng)論 0 0
  • 今晚天氣稍微變冷了許多,從健身房出來坪蚁,冷風(fēng)嗖嗖奔穿,心里還是挺暖和的,我的健身有了一定的效果了敏晤。買了面包和水果贱田,關(guān)于水...
    天涯俠客閱讀 163評(píng)論 0 0
  • 【日精進(jìn)打卡第43天】 【知~學(xué)習(xí)】 《六項(xiàng)精進(jìn)》2遍 共75遍 《大學(xué)》2遍 共76遍 【經(jīng)典名句分享】 成功的...
    斐然之夏閱讀 134評(píng)論 0 0