Java並發筆記

來源:互聯網
上載者:User

標籤:queue   zed   catch   迴圈   tac   cas   鎖對象   好的   ant   

為什麼需要並行?    – 業務要求    – 效能    並行計算還出於業務模型的需要        – 並不是為了提高系統效能,而是確實在業務上需要多個執行單元。        – 比如HTTP伺服器,為每一個Socket串連建立一個處理線程        – 讓不同線程承擔不同的業務工作        – 簡化任務調度    Linus Torvalds :並行計算只有在 *影像處理* 和 *服務端編程* 2個領域可以使用,並且它在這2個領域確實有著大量廣泛的使用。但是在其它任何地方,並行計算毫無建樹!    計算密集型    在多核時代,一般沒有必要特別區分並發和並行 同步(synchronous)和非同步(asynchronous)    ? 並發(Concurrency)和並行(Parallelism)    ? 臨界區    ? 阻塞(Blocking)和非阻塞(Non-Blocking)        – 阻塞和非阻塞通常用來形容多線程間的相互影響。比如一個線程佔用了臨界區資源,那麼其它所有需要這個資源的線程就必須在這個臨界區中進行等待,等待會導致線程掛起。這種情況就是阻塞。此時,如果佔用資源的線程一直不願意釋放資源,那麼其它所有阻塞在這個臨界區上的線程都不能工作。        – 非阻塞允許多個線程同時進入臨界區    ? 鎖(Deadlock)、饑餓(Starvation)和活鎖(Livelock)    ? 並行的層級並發層級    – 阻塞    – 非阻塞        – 無障礙         – 無鎖        – 無等待有關並行的2個重要定律    ? Amdahl定律(阿姆達爾定律)    ? Gustafson定律(古斯塔夫森)進程切換是一個重量級的操作,需要消耗大量的計算資源在Java中的線程會直接映射到作業系統的線程上去Thread t1 = new Thread();t1.start(); // 開啟線程進入就緒狀態Thread t2 = new Thread();t2.run();   // 不能開啟線程,在本線程內執行run方法  繼承Thread重寫run方法,MyThread extends Threadnew Thread(new Runnable() {}).start();Thread.stop()不建議使用@Deprecated,太過暴力,類似於Linux強制殺死進程:kill -9 thread_idpublic static native void sleep(long millis) throws InterruptedExceptionpublic void run() {    while (true) {        if (Thread.currentThread().isInterrupted()) {            System.out.println("Interruted!");            break;        }        try {            Thread.sleep(2000);        } catch (InterruptedException e) {            System.out.println("Interruted When Sleep");            // 設定中斷狀態,拋出異常後會清除中斷標記位 ********            Thread.currentThread().interrupt();        }        Thread.yield();    }}suspend()、resume()等待線程結束(join)和謙讓(yeild)    join的本質:        while(isAlive()) {            wait(0);        }        線程執行完畢後,系統會調用notifyAll();   ===> 可以不需要線上程執行個體上使用wait()和notifyAll()守護線程    ? 在後台默默地完成一些系統性的服務,比如記憶體回收線程、 JIT線程就可以理解為守護線程    ? 當一個Java應用內,只有守護線程時,Java虛擬機器就會自然退出        Thread t = new DaemonT();        t.setDaemon(true);        t.start();    高優先順序的線程更容易再競爭中獲勝基本的線程同步操作    ? synchronized        – 指定加鎖對象:對給定對象加鎖,進入同步代碼前要獲得給定對象的鎖。                public void run() {                    for(int j = 0; j < 10000000; j++) {                        synchronized(instance) {                            i++;                        }                    }                }        – 直接作用於執行個體方法:相當於對當前執行個體加鎖,進入同步代碼前要獲得當前執行個體的鎖。                public synchronized void increase(){                    i++;                }        – 直接作用於靜態方法:相當於對當前類加鎖,進入同步代碼前要獲得當前類的鎖。                public static synchronized void increase(){                    i++                }        ? Object.wait() Obejct.notify()            public static class T1 extends Thread {                public void run() {                    synchronized (object) {                        System.out.println(System.currentTimeMillis()+":T1 start!");                        try {                            System.out.println(System.currentTimeMillis() + ":T1 wait for object ");                            object.wait();                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                        System.out.println(System.currentTimeMillis()+":T1 end!");                    }                }            }            public static class T2 extends Thread {                public void run() {                    synchronized (object) {                        System.out.println(System.currentTimeMillis() +":T2 start! notify one thread");                        object.notify();                        System.out.println(System.currentTimeMillis()+":T2 end!");                        try {                            Thread.sleep(2000);                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                }            }            1425224592258:T1 start!            1425224592258:T1 wait for object            1425224592258:T2 start! notify one thread            1425224592258:T2 end!            1425224594258:T1 endnotify() VS notifyAll()    notify()隨機喚醒一個線程,notifyAll()喚醒全部等待此監視器的線程,讓他們去競爭這個監視器的使用權》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》Java記憶體模型和安全執行緒     ? 原子性                   原子性是指一個操作是不可中斷的。即使是在多個線程一起執行的時候,一個操作一旦開始,就不會被其它線程幹擾。       ? 有序性        在並發時,程式的執行可能就會出現亂序。        一條指令的執行是可以分為很多步驟的(*資料旁路技術*&*指令重排*可以使流水線更加流暢,指令重排不能出現語義問題)            – 取指 IF            – 解碼和取寄存器運算元 ID            – 執行或者有效地址計算 EX            – 儲存空間訪問 MEM            – 寫回 WB        ? 可見度        可見度是指當一個線程修改了某一個共用變數的值,其他線程是否能夠立即知道這個修改。            – 編譯器最佳化            – 硬體最佳化(如寫吸收,批操作)        Java虛擬機器層面的可見度(volatile)        ? Happen-Before        ? 程式順序原則:一個線程內保證語義的串列性        ? volatile規則:volatile變數的寫,先發生於讀,這保證了volatile變數的可見度        ? 鎖規則:解鎖(unlock)必然發生在隨後的加鎖(lock)前        ? 傳遞性:A先於B,B先於C,那麼A必然先於C        ? 線程的start()方法先於它的每一個動作        ? 線程的所有操作先於線程的終結(Thread.join())        ? 線程的中斷(interrupt())先於被中斷線程的代碼        ? 對象的建構函式執行結束先於finalize()方法        ? 安全執行緒的概念        指某個函數、函數庫在多線程環境中被調用時,能夠正確地處理各個線程的局部變數,使程式功能正確完成。    ReentrantLock(重入鎖 )是synchronized關鍵字的增強,目前兩者效能不相上下。ReentrantLock    可重新進入        可多次加鎖    可中斷        發生死結時,可啟用一個守護線程去中斷某一線程從而達到解鎖目的    可限時        避免死結和長期等待鎖    公平鎖         公平鎖雖然不會產生饑餓但是由於公平鎖需要解決排隊問題(先到先得),所以效能較非公平鎖差,沒有特殊要求沒必要使用公平鎖。JDK並發包--並發容器及典型源碼分析    ?? 集合封裝        ? HashMap --> 適用小並發量,串列解決方案,非高並發解決方案                public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {                    return new SynchronizedMap<>(m);                }        ? List                public static <T> List<T> synchronizedList(List<T> list) {                    return (list instanceof RandomAccess ?                            new SynchronizedRandomAccessList<>(list) :                            new SynchronizedList<>(list));                }        ? Set                public static <T> Set<T> synchronizedSet(Set<T> s) {                    return new SynchronizedSet<>(s);                }        ?? ConcurrentHashMap        ConcurrentHashMap(HashMap底層使用數組實現,因此為實現大規模高並發,可將整個數組分成N個段<Segment>,一個就可供N個線程同時寫入資料,理論提高效率N倍)        put()方法各個Segment有各自的鎖,get()方法無鎖,但是在size()方法中需要拿到所有Segment的鎖後才能統計資料,但size()方法並非一個高頻率調用的函數。        之所是高效能,是因為不會隨隨便便就加鎖,而是經過自旋等待在有必要的時候才加鎖。        ?? BlockingQueue        阻塞隊列,是一個介面,安全執行緒,不是一個高效能的容器,但是BlockingQueue是一個非常好的**在多個線程中共用資料的容器**        若為空白隊列,此時有線程嘗試讀取資料,則此讀的線程會等待,直到有另外線程往隊列中寫入資料,則讀的線程就會被喚醒並且讀取資料;        若隊列已經寫滿了,則寫入的線程就會等待,直到有線程讀取資料有空閑空間後才能寫入隊列;        因此Blocking會引起線程阻塞。        BlockingQueue作為生產者消費者容器很方便。            put()、take()        實現:ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue。        ?? ConcurrentLinkedQueue        類似ConcurrentHashMap的高效能Queue,內部使用了大量的無鎖操作。offer()、poll()        ? BlockingQueue VS ConcurrentLinkedQueue            在並發編程中我們有時候需要使用安全執行緒的隊列。如果我們要實現一個安全執行緒的隊列有兩種實現方式:一種是使用**阻塞演算法**,另一種是使用**非阻塞演算法**。使用阻塞演算法的隊列可以用一個鎖(入隊和出隊用同一把鎖)或兩個鎖(入隊和出隊用不同的鎖)等方式來實現,而非阻塞的實現方式則可以使用迴圈CAS的方式來實現。

 

Java並發筆記

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.