第五章 并行模式和算法

1. 單例模式

  • 單例模式是一種對象創(chuàng)建模式权埠,用于產(chǎn)生一個(gè)對象的具體實(shí)例榨了,確保系統(tǒng)中一個(gè)類只產(chǎn)生一個(gè)實(shí)例。有兩大好處:
  1. 對于頻繁使用的對象攘蔽,可以省略new操作花費(fèi)的時(shí)間阻逮,對于一些重量級對象,是一筆可觀的系統(tǒng)開銷秩彤。
  2. 減輕GC壓力叔扼,縮短GC停頓時(shí)間。
//內(nèi)存開銷大漫雷,并發(fā)不安全
class Single1{
    private static final Single1 SINGLE1 = new Single1();
    private Single1() {
    }
    public static Single1 getInstance() {
        return SINGLE1;
    }
}
//并發(fā)安全瓜富,有鎖性能開銷大,內(nèi)存開銷小
class Single2{
    private static Single4 single2 = null;
    private Single2() {
    }
    public static synchronized Single2 getInstance() {
        if(single2 == null) {
            single2 = new Single4();
        }
        return single2;
    }
}

//丑陋降盹、復(fù)雜与柑,低版本jdk不適用
class Single3{
    private static volatile Single3 single3;
    private Single3() { 
    }
    public static Single3 getInstance() {
        if(single3 == null) {
            synchronized(Single3.class) {
                if(single3 == null) {
                    single3 = new Single3();
                }
            }
        }
        return single3;
    }
}
//并發(fā)安全,無鎖性能高,內(nèi)存開銷小价捧,巧妙利用虛擬機(jī)類加載機(jī)制
class Single4{
    private Single4() {
    }
    private static class Inner{
        private static final Single4 SINGLE4 = new Single3();
    }
    public static Single4 getInstance() {
        return Inner.SINGLE4;
    }
}

2. 不變模式

  • 加鎖操作有一定的性能損耗丑念。
  • 不變模式:天生多線程友好的。一旦對象被創(chuàng)建结蟋,則它的內(nèi)部狀態(tài)將永遠(yuǎn)不會發(fā)生改變脯倚。沒有任何一個(gè)線程可以修改其內(nèi)部狀態(tài)和數(shù)據(jù),同時(shí)其內(nèi)部狀態(tài)也不會發(fā)生改變嵌屎。
  • 只讀屬性:只讀屬性不會被其他修改推正,但是自身有可能變化,比如對象的存活時(shí)間會隨著時(shí)間推移變化宝惰。
  • 不變模式的主要使用場景需要滿足兩個(gè)條件:
  1. 當(dāng)對象創(chuàng)建后植榕,其內(nèi)部狀態(tài)和數(shù)據(jù)不再發(fā)生任何變化。
  2. 對象需要被共享尼夺,被多線程頻繁訪問尊残。

【如何實(shí)現(xiàn)不變模式】:

  1. 去除setter和其他所有修改自身屬性的方法。
  2. 將所有屬性設(shè)為私有淤堵,并用final標(biāo)記夜郁,確保其不可修改。
  3. 確保沒有子類可以重載修改它的行為粘勒。
  4. 有一個(gè)可以創(chuàng)建完整對象的構(gòu)造函數(shù)竞端。
//final 起關(guān)鍵作用
public final class Product {
    private final String no;
    private final String name;
    private final double price;
    public Product(String no, String name, double price) {
        super();
        this.no = no;
        this.name = name;
        this.price = price;
    }
    public String getNo() {
        return no;
    }
    public String getName() {
        return name;
    }
    public double getPrice() {
        return price;
    }
}

主要不變模式:

java.lang.String
java.lang.Boolean
java.lang.Byte
java.lang.Character
java.lang.Double
java.lang.Float
java.lang.Integer
java.lang.Long
java.lang.Short

3. 生產(chǎn)者-消費(fèi)者模式

  • 生產(chǎn)者-消費(fèi)者模式提供了多線程間協(xié)作的良好解決方案。生產(chǎn)者負(fù)責(zé)提交用戶請求庙睡,消費(fèi)者負(fù)責(zé)處理任務(wù)事富,兩者通過共享內(nèi)存緩沖區(qū)進(jìn)行通信。
  • 內(nèi)存緩沖區(qū)避免了生產(chǎn)者和消費(fèi)者的直接通信乘陪,從而將生產(chǎn)者和消費(fèi)者解耦统台。同時(shí)允許生產(chǎn)者和消費(fèi)者在執(zhí)行速度上存在時(shí)間差。

BlockingQueue實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者是一個(gè)不錯(cuò)的選擇啡邑,但是BlockingQueue并不是一個(gè)高性能的實(shí)現(xiàn)贱勃,它完全使用鎖和阻塞等待來實(shí)現(xiàn)線程間的同步。在高并發(fā)場合谤逼,它的性能不是特別的優(yōu)越贵扰。可以用無鎖的Disruptor實(shí)現(xiàn)流部。Disruptor使用無鎖的方式實(shí)現(xiàn)了一個(gè)環(huán)形隊(duì)列戚绕,生產(chǎn)者和消費(fèi)者都是用CAS操作來處理環(huán)形隊(duì)列中的數(shù)據(jù)。

4. Future模式

  • 核心思想是異步調(diào)用枝冀,當(dāng)我們需要調(diào)用一個(gè)函數(shù)方法時(shí)舞丛,如果這個(gè)函數(shù)執(zhí)行很慢而我們又不是立刻需要結(jié)果耘子,可以讓被調(diào)者立刻返回,讓他在后臺慢慢處理這個(gè)請求球切,對調(diào)用者來說谷誓,可以先處理一些其他任務(wù),在真正需要數(shù)據(jù)的場合再去嘗試獲得需要的數(shù)據(jù)吨凑。

public interface Data {
    public String getResult();
}
//FutrureData是RealData的虛擬實(shí)現(xiàn)捍歪,可以很快被構(gòu)造并返回。如果數(shù)據(jù)沒準(zhǔn)備好怀骤,那么程序會阻塞费封。
public class FutureData implements Data {
    protected RealData realData = null;
    protected boolean isReady = false;
    public synchronized void setRealData(RealData realData) {
        if(isReady) {
            return;
        }
        this.realData = realData;
        isReady = true;
        notifyAll();
    }
    @Override
    public synchronized String getResult() {
        while(!isReady) {
            try {
                wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return realData.result;
    }
}

public class RealData implements Data{
    protected final String result;
    public RealData(String para) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 10; i++) {
            sb.append(para);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        result = sb.toString();
    }
    @Override
    public String getResult() {
        return result;
    }
}

public class Client {
    public Data request(final String queryStr) {
        final FutureData futureData = new FutureData();
        new Thread() {
            public void run() {
                RealData realData = new RealData(queryStr);
                futureData.setRealData(realData);
            }
        }.start();
        return futureData;
    }
}

public class Main {
    public static void main(String[] args) {
        Client client = new Client();
        Data data = client.request("name");
        System.out.println("請求完畢");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("真實(shí)數(shù)據(jù)"+data.getResult());
    }
}

5. JDK的Future

image.png
public interface Callable<V> {   
      V   call()   throws Exception;   
}
public interface Future<V> {  
    boolean cancel(boolean mayInterruptIfRunning);  
    boolean isCancelled();  
    boolean isDone();  
    V get() throws InterruptedException, ExecutionException;  
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;  
}  
public class CallableDemo implements Callable<Integer> {  
    private int sum;  
    @Override  
    public Integer call() throws Exception {  
        System.out.println("Callable子線程開始計(jì)算啦焕妙!");  
        Thread.sleep(2000);  
          
        for(int i=0 ;i<5000;i++){  
            sum=sum+i;  
        }  
        System.out.println("Callable子線程計(jì)算結(jié)束蒋伦!");  
        return sum;  
    }  
}

ExecutorService es = Executors.newSingleThreadExecutor();  
//創(chuàng)建Callable對象任務(wù)  
CallableDemo calTask=new CallableDemo();  
//提交任務(wù)并獲取執(zhí)行結(jié)果  
Future<Integer> future =es.submit(calTask);  
//關(guān)閉線程池  
es.shutdown(); 
 
ExecutorService es = Executors.newSingleThreadExecutor();  
//創(chuàng)建Callable對象任務(wù)  
CallableDemo calTask=new CallableDemo();  
//創(chuàng)建FutureTask  
FutureTask<Integer> futureTask=new FutureTask<>(calTask);  
//執(zhí)行任務(wù)  
es.submit(futureTask);  
//關(guān)閉線程池  
es.shutdown();  
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市焚鹊,隨后出現(xiàn)的幾起案子痕届,更是在濱河造成了極大的恐慌,老刑警劉巖末患,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件研叫,死亡現(xiàn)場離奇詭異,居然都是意外死亡璧针,警方通過查閱死者的電腦和手機(jī)嚷炉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來探橱,“玉大人申屹,你說我怎么就攤上這事∷砀啵” “怎么了哗讥?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長胞枕。 經(jīng)常有香客問我杆煞,道長,這世上最難降的妖魔是什么腐泻? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任决乎,我火速辦了婚禮,結(jié)果婚禮上派桩,老公的妹妹穿的比我還像新娘瑞驱。我一直安慰自己,他們只是感情好窄坦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布唤反。 她就那樣靜靜地躺著凳寺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪彤侍。 梳的紋絲不亂的頭發(fā)上肠缨,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音盏阶,去河邊找鬼晒奕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛名斟,可吹牛的內(nèi)容都是我干的脑慧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼砰盐,長吁一口氣:“原來是場噩夢啊……” “哼闷袒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起岩梳,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤囊骤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后冀值,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體也物,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年列疗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滑蚯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡抵栈,死狀恐怖告材,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情竭讳,我是刑警寧澤创葡,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站绢慢,受9級特大地震影響灿渴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜胰舆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一骚露、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缚窿,春花似錦棘幸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吨悍。三九已至,卻和暖如春蹋嵌,著一層夾襖步出監(jiān)牢的瞬間育瓜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工栽烂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留躏仇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓腺办,卻偏偏與公主長得像焰手,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子怀喉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

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

  • 第5章 多線程編程 5.1 線程基礎(chǔ) 5.1.1 如何創(chuàng)建線程 在java要?jiǎng)?chuàng)建線程书妻,一般有==兩種方式==:1)...
    AndroidMaster閱讀 1,793評論 0 11
  • 三月份的時(shí)候,公司的OA給我發(fā)了一封郵件磺送,大意就是很套路的感謝我一年來的付出驻子,希望未來可以繼續(xù)進(jìn)步灿意,當(dāng)時(shí)收到這封郵...
    書呆魚閱讀 252評論 1 1
  • 我第一次看見滿天星河時(shí) 也第一次遇見你 你披星戴月而來 留我滿船的星夢 我落在那銀河之上 也想要落入你的眼中 我是...
    游鳥飛雨閱讀 610評論 0 1
  • 你分明在笑 是夕陽西下的余暉 楚楚但絕不動人 你分明在笑 是莊園里的池塘 你覺得清淺 我看它是骯臟 你可還記得那日...
    曉朔一一閱讀 190評論 0 0
  • 今晚作業(yè)不是很多缤剧,飯前就把老師布置的作業(yè)都做完了馅袁。 吃完飯我們就背古詩,一直背到現(xiàn)在荒辕,還有三首長的沒背過呢汗销。...
    史曉輝閱讀 204評論 0 8