Java語言從設(shè)計之初就把多線程作為語言的核心, 至少從以下幾點可以看出:
貢嘎網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站開發(fā)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)于2013年創(chuàng)立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
1. Object對象的wait和notify機制。
2. Thread類在lang包中。
3. synchronized volatile關(guān)鍵字。
雖然多線程是Java語言本身的特性,但是線程并不是Java語言獨有的東西,而是操作系統(tǒng)的特性。Java在語言層面進行了封裝,使其使用更簡單。
多線程存在的價值在哪里呢? 內(nèi)存讀寫,磁盤IO, 網(wǎng)絡(luò)傳輸?shù)乃俾蔬h遠低于CPU處理數(shù)據(jù)的速度。所以在大部分場景下,CPU是閑置的。有了多線程,就可以更多地壓榨CPU。所以,多線程在Web服務(wù)器,Lucene這類IO密集型的應(yīng)用中大行其道。
多線程,知識點龐雜,但常用的核心知識點只有兩個: 資源同步 和 線程池。
學(xué)習(xí)多線程,私以為這樣的先后順序比較好。
step1: 學(xué)習(xí)多線程的創(chuàng)建和運行, Thread類和Runnable接口, 通常自定義類是實現(xiàn)Runnable接口,并非Thread類。
public class ThreadDemo {
static class Worker impelements Runnable{
private String name;
public Worker(String name){
this.name = name;
}
public void run(){
System.out.println(this.name+": "+Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread a1 = new Thread(new Worker("nameA"));
Thread a2 = new Thread(new Worker("nameB"));
a1.start();
a2.start();
}
}
step2: 學(xué)習(xí)synchronized/volatile關(guān)鍵字
由于內(nèi)存讀寫遠比CPU執(zhí)行的速度慢,出于提升性能的考慮,計算機設(shè)計者在CPU和內(nèi)存之間架設(shè)了緩存,就是通常我們看到的L1, L2, L3。1個CPU周期需要0.3ns,L1緩存只需要0.9ns, 內(nèi)存訪問需要120ns。 差距達百倍, 可見緩存對性能的提升。如果我們在一個線程里讀寫一個變量,將初始值加到緩存后, CPU只需和緩存之間交互就可以了。
由于線程之間并不共享緩存,所以多個線程讀寫同一個變量時,就有可能出現(xiàn)不一致的情況。多個線程出現(xiàn)了信息的不對稱, 如何解決這個問題呢? 就像銀行辦理業(yè)務(wù)一樣,每個人辦理業(yè)務(wù)前先取個號。這個號就類似Java里面的鎖機制。 synchronized就是Java的內(nèi)置鎖。 volatile可以看作synchronized的簡化版, 因為它只能適用于某些特定的場景:
1. 修改變量不依賴其當(dāng)前的值
2. 變量不跟其他變量一起對外作為整體
關(guān)于volatile的學(xué)習(xí),個人覺得IBM的Java theory and practice Managing volatility
是極好的學(xué)習(xí)資料。
step3: 學(xué)習(xí)ReentrantLock。了解了鎖的使用場景后,可以先學(xué)習(xí)JUC實現(xiàn)的鎖,最簡單的就是ReentrantLock。ReentrantLock是互斥鎖,可作為synchronized的代替品。
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo {
static class Counter implements Runnable{
private int count;
private ReentrantLock lock = new ReentrantLock();
public void run(){
try{
lock.lock();
count +=1;
}finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
public static void main(String[] args) throws InterruptedException {
Counter a1 = new Counter();
for(int i=0;i<1000;i++){
new Thread(a1).start();
}
Thread.sleep(1000);
System.out.println(a1.getCount());
}
}
使用了ReentrantLock后,最好是能理解鎖的實現(xiàn)原理,即大名頂頂?shù)腁QS。但是學(xué)習(xí)AQS之前,需要一些預(yù)備知識。
1. volatile關(guān)鍵字的使用場景及限制
2. Unsafe.compareAndSwap的使用
3. Unsafe.park/unpark的使用
4. 數(shù)據(jù)結(jié)構(gòu)鏈表的原理
整個JUC的鎖,線程安全的隊列都是基于AQS構(gòu)建的。
step4: 學(xué)習(xí)AQS的原理。AQS基于鏈表構(gòu)建的隊列來存儲爭用鎖的線程。當(dāng)線程沒有獲取到鎖,就會使用Unsafe.park將線程掛起;其他的線程釋放鎖時,就會調(diào)用Unsafe.unpark將掛起的線程恢復(fù)。
step5: 了解了AQS的原理后,再學(xué)習(xí)ReentrantReadWriteLock, Semaphore, Phase, CountDownLatch, CyclicBarrier 這些同步工具,就沒那么難理解了。
step6: 學(xué)習(xí)BlockingQueue及其子類。 各種阻塞隊列,使用頻度比較高的是ArrayBlockingQueue, LinkedBlockingQueue.
step7: 學(xué)習(xí)線程池,主要是ThreadPoolExecutor類, ThreadPoolExecutor的核心是Worker類,每個Worker對應(yīng)著一個線程。需要注意的是使用ThreadPoolExecutor時,阻塞隊列一定要要指定大小。不然線程池的RejectPolicy就不起作用了。 具體的細節(jié)需要更深入的分析。
關(guān)于多線程的知識點, 一篇筆記是遠遠不夠的,本文僅僅梳理學(xué)習(xí)的脈絡(luò)。
參考文檔:
https://www.ibm.com/developerworks/library/j-jtp06197/index.html
文章題目:Java基礎(chǔ)學(xué)習(xí)之-多線程學(xué)習(xí)知識點的學(xué)習(xí)
地址分享:http://jinyejixie.com/article46/jopohg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機、標(biāo)簽優(yōu)化、營銷型網(wǎng)站建設(shè)、網(wǎng)站內(nèi)鏈、網(wǎng)站策劃、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)