我們先來研究下JAVA的多線程的並發編程和CPU時鍾振盪的關系吧
老規矩,先科普
我們的操作系統在DOS以前都是單任務的
什么是單任務呢?就是一次只能做一件事
你復制文件的時候,就不能重命名了
那么現在的操作系統,我一邊在這邊寫BLOG,一邊聽歌,一邊開着QQ,一邊……………………
顯然,現在的操作系統都是多任務的操作系統
操作系統對多任務的支持是怎么樣的呢?
每打開一個程序,就啟動一個進程,為其分配相應空間(主要是運行程序的內存空間)
這其實就支持並發運行了
CPU有個時鍾頻率,表示每秒能執行CPU指令的次數,
在每個時鍾周期內,CPU實際上只能執行一條(或者多條指令)。
操作系統對進程線程進行管理,
輪流(不是按順序)為每個進程分配很短的一段時間(不一定均分),
然后在每個進程的內部,程序代碼自己處理該進程內部線程的時間分配,
多個線程之間相互切換着去執行,
因為切換的時間非常非常短
因此,給人的感覺就是這多個任務、多個線程是在並發運行的
其實,從微觀角度來看,
程序的運行還是異步的。
既然都是異步運行的
那么
我們的多線程運行
其實也只是CPU也只是一直在串行的運行着
根本就沒有同時運行啊?
既然這樣
那么我們多線程又有什么意義呢?
我們又知道
Cpu的運算速度實在是太快了
但是我們I/O的讀取速度
網絡的傳輸熟讀
數據庫的連接--讀取速度
我們操作的速度
這些和CPU運算速度比起來
實在是太慢太慢了
因此
在我們進行這些操作的時候
其實CPU在多數情況下還是空閑着的
在這種情況下
我們運行多個任務多個線程
那么在進程A需要進行IO等操作時
CPU空閑就可以進行進程B的相關操作
而不是像串行的那樣一定要線程A運行完了才能運行線程B
這也就提高了CPU的利用率
可能有些童鞋會在某些論壇或者什么地方看到
有關java多線程降低CPU運算速度的討論和說法
這又是怎么回事呢?
其實,這個問題的關鍵是:
你到底要讓CPU干嘛?
如果你讓CPU進行的全是內部運算
(沒有任何I/O 網絡 數據庫訪問 等等…… )
那么,人為地硬折開CPU內部運算
用來給多個線程"分時"運算
那么CPU運算速度只能更慢
但是
如果你的業務不全是CPU內部運算
還有網絡\數據庫訪問\I/O(如GUImouse操作)等等
則使用多線程有明顯的好處
說了這么多
還沒最重要的問題呢------多線程的目的
多線程的目的是為了最大限度的利用CPU資源
好了
那么我們繼續討論CPU的問題
CPU中
主頻=外頻×倍頻
主頻越高
一個時鍾周期里面完成的指令數也越多
當然cpu的速度也就越快了
以前提高CPU運算速度的方法
就是提高CPU主頻
但是隨着時間的發展
cpu主頻在一定程度上
已經達到了物理極限,很難再提高了
那么我們想再繼續提高CPU性能應該怎么辦呢?
我們知道
傳統的CPU
只有一個內核
這個內核也只用同時運行一個線程
現在要提高CPU性能
我們可以在CPU的一個內核上
允許運行多個操作
從硬件級上實現多線程並發運行
為了提高CPU的運算性能
只有使用具有超線程技術的多核CPU
-------------我想這才是JAVA支持多線程並發運行的長久意義所在
說了這么多
再來回到我們的主題吧
java中多線程
1. 關於內存
前面已經說過
在操作系統下
每打開一個程序
系統就會為啟動一個進程
為進程分配系統資源(運行程序所需的內存等)
在JAVA中
所有線程都歸JVM調度
那么
在JAVA中的線程和系統下的進程在內存使用方面又會有哪些異同呢?
而在Java中所有變量都儲存在主存中
對於所有線程都是共享的(在同一進程中)
每條線程都有自己的工作內存(Working Memory)
工作內存中保存的是主存中某些變量的拷貝
線程對所有變量的操作都是在工作內存中進行
線程之間無法相互直接訪問
變量傳遞均需要通過主存完成
但是在程序內部可以互相調用(通過對象方法)
所有線程間的通信相對簡單,速度也很快
進程間的內部數據和狀態都是相互完全獨立的
而進程間通信大多數情況是必須通過網絡實現
線程本身的數據通常只有寄存器數據
以及一個程序執行時使用的堆棧
所以線程的切換比進程切換的負擔要小
關於線程調度
前面說了
CPU對於各個線程的調度是隨機的(分時調度)
在Java程序中,JVM負責線程的調度
線程調度是指------按照特定的機制為多個線程分配CPU的使用權
調度的模式有兩種:
分時調度和搶占式調度。
分時調度是所有線程輪流獲得CPU使用權,並平均分配每個線程占用CPU的時間;
搶占式調度是根據線程的優先級別來獲取CPU的使用權。
JVM的線程調度模式采用了搶占式模式。
既然是搶占調度
那么我們就能通過設置優先級來“有限”的控制線程的運行順序
注意“有限”一次