我們?cè)趯?shí)現(xiàn)多線程廣播屏幕截圖的時(shí)候
因?yàn)镃PU對(duì)多個(gè)線程之間的執(zhí)行順序是隨機(jī)的
也就導(dǎo)致了我們發(fā)圖片的時(shí)間間隔的不確定性
從而導(dǎo)致了有些圖片從開(kāi)始發(fā)到發(fā)完的時(shí)間的不確定性
嚴(yán)重降低了系統(tǒng)的實(shí)時(shí)性
(實(shí)際上迷殿,在TCP模式下用線程池多線程隨機(jī)發(fā)送圖片改良下的遠(yuǎn)程監(jiān)控系統(tǒng)儿礼,如果服務(wù)器端放電影,觀測(cè)客戶端庆寺,會(huì)發(fā)現(xiàn)經(jīng)常會(huì)出現(xiàn)電影“倒著放”的現(xiàn)象蚊夫,原因也就是這個(gè)還有救網(wǎng)絡(luò)路由時(shí)間的不確定性)
要解決這個(gè)問(wèn)題
那么
我們先來(lái)研究下JAVA的多線程的并發(fā)編程和CPU時(shí)鐘振蕩的關(guān)系吧
老規(guī)矩,先科普
我們的操作系統(tǒng)在DOS以前都是單任務(wù)的
什么是單任務(wù)呢懦尝?就是一次只能做一件事
你復(fù)制文件的時(shí)候知纷,就不能重命名了
那么現(xiàn)在的操作系統(tǒng),我一邊在這邊寫B(tài)LOG陵霉,一邊聽(tīng)歌琅轧,一邊開(kāi)著QQ,一邊……………………
顯然踊挠,現(xiàn)在的操作系統(tǒng)都是多任務(wù)的操作系統(tǒng)
操作系統(tǒng)對(duì)多任務(wù)的支持是怎么樣的呢乍桂?
每打開(kāi)一個(gè)程序,就啟動(dòng)一個(gè)進(jìn)程效床,為其分配相應(yīng)空間(主要是運(yùn)行程序的內(nèi)存空間)
這其實(shí)就支持并發(fā)運(yùn)行了
CPU有個(gè)時(shí)鐘頻率模蜡,表示每秒能執(zhí)行CPU指令的次數(shù),
在每個(gè)時(shí)鐘周期內(nèi)扁凛,CPU實(shí)際上只能執(zhí)行一條(或者多條指令)。
操作系統(tǒng)對(duì)進(jìn)程線程進(jìn)行管理闯传,
輪流(不是按順序)為每個(gè)進(jìn)程分配很短的一段時(shí)間(不一定均分)谨朝,
然后在每個(gè)進(jìn)程的內(nèi)部,程序代碼自己處理該進(jìn)程內(nèi)部線程的時(shí)間分配甥绿,
多個(gè)線程之間相互切換著去執(zhí)行字币,
因?yàn)榍袚Q的時(shí)間非常非常短
因此,給人的感覺(jué)就是這多個(gè)任務(wù)共缕、多個(gè)線程是在并發(fā)運(yùn)行的
其實(shí)洗出,從微觀角度來(lái)看,
程序的運(yùn)行還是異步的图谷。
既然都是異步運(yùn)行的
那么
我們的多線程運(yùn)行
其實(shí)也只是CPU也只是一直在串行的運(yùn)行著
根本就沒(méi)有同時(shí)運(yùn)行棒婊睢阱洪?
既然這樣
那么我們多線程又有什么意義呢?
我們又知道
Cpu的運(yùn)算速度實(shí)在是太快了
但是我們I/O的讀取速度
網(wǎng)絡(luò)的傳輸熟讀
數(shù)據(jù)庫(kù)的連接--讀取速度
我們操作的速度
這些和CPU運(yùn)算速度比起來(lái)
實(shí)在是太慢太慢了
因此
在我們進(jìn)行這些操作的時(shí)候
其實(shí)CPU在多數(shù)情況下還是空閑著的
在這種情況下
我們運(yùn)行多個(gè)任務(wù)多個(gè)線程
那么在進(jìn)程A需要進(jìn)行IO等操作時(shí)
CPU空閑就可以進(jìn)行進(jìn)程B的相關(guān)操作
而不是像串行的那樣一定要線程A運(yùn)行完了才能運(yùn)行線程B
這也就提高了CPU的利用率
可能有些童鞋會(huì)在某些論壇或者什么地方看到
有關(guān)java多線程降低CPU運(yùn)算速度的討論和說(shuō)法
這又是怎么回事呢?
其實(shí)菠镇,這個(gè)問(wèn)題的關(guān)鍵是:
你到底要讓CPU干嘛冗荸?
如果你讓CPU進(jìn)行的全是內(nèi)部運(yùn)算
(沒(méi)有任何I/O??? 網(wǎng)絡(luò)?? 數(shù)據(jù)庫(kù)訪問(wèn)? 等等…… )
那么,人為地硬折開(kāi)CPU內(nèi)部運(yùn)算
用來(lái)給多個(gè)線程"分時(shí)"運(yùn)算
那么CPU運(yùn)算速度只能更慢
但是
如果你的業(yè)務(wù)不全是CPU內(nèi)部運(yùn)算
還有網(wǎng)絡(luò)\數(shù)據(jù)庫(kù)訪問(wèn)\I/O(如GUImouse操作)等等
則使用多線程有明顯的好處
說(shuō)了這么多
還沒(méi)最重要的問(wèn)題呢------多線程的目的
多線程的目的是為了最大限度的利用CPU資源
好了
那么我們繼續(xù)討論CPU的問(wèn)題??
CPU中
主頻=外頻×倍頻
主頻越高
一個(gè)時(shí)鐘周期里面完成的指令數(shù)也越多
當(dāng)然cpu的速度也就越快了
以前提高CPU運(yùn)算速度的方法
就是提高CPU主頻
但是隨著時(shí)間的發(fā)展
cpu主頻在一定程度上
已經(jīng)達(dá)到了物理極限利耍,很難再提高了
那么我們想再繼續(xù)提高CPU性能應(yīng)該怎么辦呢蚌本?
我們知道
傳統(tǒng)的CPU
只有一個(gè)內(nèi)核
這個(gè)內(nèi)核也只用同時(shí)運(yùn)行一個(gè)線程
現(xiàn)在要提高CPU性能
我們可以在CPU的一個(gè)內(nèi)核上
允許運(yùn)行多個(gè)操作
從硬件級(jí)上實(shí)現(xiàn)多線程并發(fā)運(yùn)行
為了提高CPU的運(yùn)算性能
只有使用具有超線程技術(shù)的多核CPU
-------------我想這才是JAVA支持多線程并發(fā)運(yùn)行的長(zhǎng)久意義所在
說(shuō)了這么多
再來(lái)回到我們的主題吧
java中多線程
1.? 關(guān)于內(nèi)存
前面已經(jīng)說(shuō)過(guò)
在操作系統(tǒng)下
沒(méi)打開(kāi)一個(gè)程序
系統(tǒng)就會(huì)為啟動(dòng)一個(gè)進(jìn)程
為進(jìn)程分配系統(tǒng)資源(運(yùn)行程序所需的內(nèi)存等)
在JAVA中
所有線程都?xì)wJVM調(diào)度
那么
在JAVA中的線程和系統(tǒng)下的進(jìn)程在內(nèi)存使用方面又會(huì)有哪些異同呢?
而在Java中所有變量都儲(chǔ)存在主存中
對(duì)于所有線程都是共享的(在同一進(jìn)程中)
每條線程都有自己的工作內(nèi)存(Working Memory)
工作內(nèi)存中保存的是主存中某些變量的拷貝
線程對(duì)所有變量的操作都是在工作內(nèi)存中進(jìn)行
線程之間無(wú)法相互直接訪問(wèn)
變量傳遞均需要通過(guò)主存完成
但是在程序內(nèi)部可以互相調(diào)用(通過(guò)對(duì)象方法)
所有線程間的通信相對(duì)簡(jiǎn)單隘梨,速度也很快
進(jìn)程間的內(nèi)部數(shù)據(jù)和狀態(tài)都是相互完全獨(dú)立的
而進(jìn)程間通信大多數(shù)情況是必須通過(guò)網(wǎng)絡(luò)實(shí)現(xiàn)
線程本身的數(shù)據(jù)通常只有寄存器數(shù)據(jù)
以及一個(gè)程序執(zhí)行時(shí)使用的堆棧
所以線程的切換比進(jìn)程切換的負(fù)擔(dān)要小
關(guān)于線程調(diào)度
前面說(shuō)了
CPU對(duì)于各個(gè)線程的調(diào)度是隨機(jī)的(分時(shí)調(diào)度)
在Java程序中程癌,JVM負(fù)責(zé)線程的調(diào)度
線程調(diào)度是指------按照特定的機(jī)制為多個(gè)線程分配CPU的使用權(quán)
調(diào)度的模式有兩種:
分時(shí)調(diào)度和搶占式調(diào)度。
分時(shí)調(diào)度是所有線程輪流獲得CPU使用權(quán)轴猎,并平均分配每個(gè)線程占用CPU的時(shí)間;
搶占式調(diào)度是根據(jù)線程的優(yōu)先級(jí)別來(lái)獲取CPU的使用權(quán)嵌莉。
JVM的線程調(diào)度模式采用了搶占式模式。
既然是搶占調(diào)度
那么我們就能通過(guò)設(shè)置優(yōu)先級(jí)來(lái)“有限”的控制線程的運(yùn)行順序
注意“有限”一次