【并發(fā)技術(shù)08】多個(gè)線程間共享數(shù)據(jù)
我們先看一個(gè)多線程間共享數(shù)據(jù)的問題:
設(shè)計(jì)四個(gè)線程,其中兩個(gè)線程每次對(duì) data 增加 1,另外兩個(gè)線程每次對(duì) data 減少 1。
從問題來看,很明顯涉及到了線程間通數(shù)據(jù)的共享,四個(gè)線程共享一個(gè) data,共同操作一個(gè) data。我們先把上面這個(gè)問題放在一邊,慢慢分析多個(gè)線程之間共享數(shù)據(jù)的一些情況,從最簡(jiǎn)單開始,分類分析完了后,到時(shí)候也好解決上面這個(gè)問題了。
1. 每個(gè)線程執(zhí)行的任務(wù)相同
這是最簡(jiǎn)單的一種情況,比如賣票,幾個(gè)線程共同操作記錄票數(shù)的那個(gè)變量,任務(wù)都是使它減一。針對(duì)這種情況,我們只需要寫一個(gè)類實(shí)現(xiàn) Runnable 接口即可,在?run()?方法中對(duì)這個(gè)票進(jìn)行減一,然后將這個(gè) Runnalbe 扔給多個(gè)線程去執(zhí)行,自然它們就操作同一個(gè) data 了。看一下代碼:
public?class?MultiThreadShareData?{????public?static?void?main(String[]?args)?{????????????????ShareData?task?=?new?ShareData();?//一個(gè)類實(shí)現(xiàn)了Runnable接口????????????????for(int?i?=?0;?i?4;?i?++)?{???//四個(gè)線程來賣票???????????????????new?Thread(task).start();????????}????}}class?ShareData?implements?Runnable?{????private?int?data?=?100;????@Override????public?void?run()?{?//賣票,每次一個(gè)線程進(jìn)來,先判斷票數(shù)是否大于0//????????while(data?>?0)?{????????????synchronized(this)?{????????????????if(data?>?0)?{????????????????????System.out.println(Thread.currentThread().getName()?+?":?"?+?data);????????????????????data--;????????????????}????????????}//????????}????}}
這很好理解,也很容易實(shí)現(xiàn),四個(gè)線程賣了 4 張票。運(yùn)行結(jié)果為:
Thread-0: 100
Thread-3: 99
Thread-2: 98
Thread-1: 97
2. 每個(gè)線程執(zhí)行不同的任務(wù)
就如上面那個(gè)題目所描述的,兩個(gè)線程執(zhí)行 data 增,兩個(gè)線程執(zhí)行 data 減。針對(duì)這種情況,我們要實(shí)現(xiàn)兩個(gè) Runnable 了,因?yàn)楹苊黠@有兩個(gè)不同的任務(wù)了,一個(gè)任務(wù)執(zhí)行 data 增,另一個(gè)任務(wù)執(zhí)行 data 減。為了便于維護(hù),可以將兩個(gè)任務(wù)方法放到一個(gè)類中,然后將 data 也放在這個(gè)類中,然后傳到不同的 Runnable 中,即可完成數(shù)據(jù)的共享。如下:
public?class?MultiThreadShareData?{????public?static?void?main(String[]?args)?{????????????????ShareData?task?=?new?ShareData();?//公共數(shù)據(jù)和任務(wù)放在task中????????for(int?i?=?0;?i?2;?i?++)?{?//開啟兩個(gè)線程增加data????????????????????????new?Thread(new?Runnable()?{?????????????????????????????@Override????????????????public?void?run()?{????????????????????task.increment();????????????????}????????????}).start();????????}????????for(int?i?=?0;?i?2;?i?++)?{?//開啟兩個(gè)線程減少data????????????????????????new?Thread(new?Runnable()?{?????????????????????????????@Override????????????????public?void?run()?{????????????????????task.decrement();????????????????}????????????}).start();????????}???????????????}}????class?ShareData?/*implements?Runnable*/?{????private?int?data?=?0;????public?synchronized?void?increment()?{?//增加data????????System.out.println(Thread.currentThread().getName()?+?":?before?:?"?+?data);????????data++;????????System.out.println(Thread.currentThread().getName()?+?":?after?:?"?+?data);????}????public?synchronized?void?decrement()?{?//減少data????????System.out.println(Thread.currentThread().getName()?+?":?before?:?"?+?data);????????data--;????????System.out.println(Thread.currentThread().getName()?+?":?after?:?"?+?data);????}}
我們看一下打印結(jié)果:
Thread-0: before : 0
Thread-0: after : 1
Thread-1: before : 1
Thread-1: after : 2
Thread-2: before : 2
Thread-2: after : 1
Thread-3: before : 1
Thread-3: after : 0
這樣寫的好處是兩個(gè)任務(wù)方法可以直接在方法名上進(jìn)行同步操作,這種模式的好處在前面的博文中已經(jīng)有說過了,封裝的好。
最后總結(jié)一下,多個(gè)線程之間共享數(shù)據(jù)主要關(guān)注兩點(diǎn)就行:一是什么任務(wù)?幾個(gè)任務(wù)?二是幾個(gè)線程?記住 一點(diǎn):幾個(gè)任務(wù)和幾個(gè)線程是沒有關(guān)系的!100 個(gè)線程可以執(zhí)行一個(gè)任務(wù),也可以執(zhí)行 2 個(gè)任務(wù),3 個(gè)任務(wù)……
如果只有一個(gè)任務(wù),那說明多個(gè)線程執(zhí)行一個(gè)任務(wù),我們只要實(shí)現(xiàn)一個(gè) Runnable 接口,把公共 data 放進(jìn) Runnable,把任務(wù)放進(jìn)去?run()?中即可(任務(wù)注意要同步),然后開啟 N 個(gè)線程去執(zhí)行這個(gè)任務(wù)即可;如果有 M 個(gè)任務(wù),那我們新建一個(gè)專門執(zhí)行任務(wù)的類,把公共的 data 放進(jìn)類中,把任務(wù)作為類中的同步方法即可,然后開啟 N 個(gè)線程,每個(gè)線程中扔一個(gè) Runnable,按照要求執(zhí)行任務(wù)類中的方法即可。
到這里,不知道大家能否體會(huì)到任務(wù)和線程的分離了,這種思想也算是面向?qū)ο蟮囊环N吧。
任務(wù)調(diào)度
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。