Java高併發程序設計

第一章  走入並行世界

 

關於並行的兩個定律: Amdahl定律 和Gustafson定律 考慮方向不同

 

Java內存模型 JMM 原子性 可見性 有序性

 

第二章 Java並行程序基礎

    

    線程創建: new Thread(Runable).start()

    線程終止: stop 方法  會立即釋放鎖,導致數據不一致問題,已經廢棄

    線程中斷: interrupt() 設置中斷標識,run方法中可以依靠這個做線程退出的邏輯處理Thread.interrupted()用來判斷

    等待和通知:wait()和notify()必須在synchronized中,涉及到鎖的操作

    掛起和繼續執行:suspend 和 resume 已經廢棄

    等待線程結束和謙讓:

              如果一個線程A依賴另外一個線程B,那就在A中執行B.join() 即 A要等待線程B結束

              yield()是讓出CPU資源,但是還是會進行資源競爭.

    volatile關鍵字:保證線程間的可見性和禁止執行重排(有序性)但是不能保證原子性  JMM

    守護線程: daemon 後臺線程,當用戶線程都結束時,守護線程也會結束,如垃圾回收線程

    

 

第三章 JDK併發包

    1.同步控制 

       1.1可重入鎖 ReentrantLock

            ReentrantLock  lock  = new ReentrantLock()

            lock.lock() 加鎖

            lock.unlock解鎖

            對同一個線程而言,可以重複的加鎖,也要解相同次數的鎖才行

            中斷響應: lock.lockInterruptibly() 會對thread.interrupt()拋出異常,對其進行處理即可

            限時申請鎖: lock.tryLock(time,timeUnit.xxx) 在限定時間內申請獲取鎖,成功返回true 失敗返回false

            公平鎖:  ReentrantLock  lock  = new ReentrantLock(true) 默認非公平,公平鎖需要維護一個線程申請鎖的隊列

       1.2 重入鎖好搭檔: Conditon 條件

             Condition condition  =  lock.newCondition()

             condition的用法類似於object.wait() 和 object.notify()

             await()方法會使當前線程等待,同時釋放當前鎖,當其他線程中使用signal()或者signalAll()方法是,線程活重新獲取鎖,繼續執行.

             當前線程被中斷時也能跳出等待.

             awaitUninterruptibly() 和 await()類似,但是不會中斷相應

             singal()喚醒一個線程,singalAll()喚醒所有線程.

             併發容器中使用兩個condition實現隊列的take和put的阻塞.見ArrayBlockingQueue源碼

        1.3 允許多線程同時訪問: 信號量 Semaphore 

              Semaphore (int permits) 或者 Semaphore (int permits,boolean fair)  數量 和 公平

              大家看方法就能猜如來如何使用了

              acquire() 獲取一個憑證

              acquireUninterruptibly() 獲取憑證對中斷響應

              tryAcquire() 不等待獲取憑證 類似 tryLock()

              tryAcquire(timeout,unit) 指定時間內獲取憑證

              release() 釋放憑證

        1.4 ReadWriteLock 讀寫鎖

              ReentrantReadWriteLock readWriteLock = new   ReentrantReadWriteLock ();

              Lock  readLock  = readWriteLock.readLock(); 讀鎖

              Lock  writeLock = readWriteLock.writeLock(); 寫鎖

              讀讀不互斥,寫寫互斥,讀寫互斥.

        1.5  CountDownLatch 倒計時器

               這個很常見不就寫了

        1.6  循環柵欄: CyclicBarrier

               和CountDownLatch類似但比其強大.

                CyclicBarrier(int parties,Runnable barrieraction)

                循環柵欄會阻塞 xxx.await()直到滿足數目才讓線程一起向下執行,且在此之前會執行一次 barrieraction中run方法 

        1.7  線程阻塞工具類: LockSupport

               它可以在線程內任意位置讓線程阻塞.

                LockSupport.park() 可以阻塞當前線程,類似的還有parkNanos(),parkUntil()等實現一個閒時的阻塞

                LockSupprot.unpark(Thread) 釋放指定線程的阻塞

    

 2. 線程複用:線程池

     這個就不浪費筆墨了,依託底層 ThreadPoolExecutor實現了幾種常用的線程池工具,大家應該都明白的.

     線程池可以根據自己的需求進行相應的自定義處理:

     ThreadPoolExecutor提供了beforeExecute() ,afterExecute(),terminated() 方法對其進行控制.

      線程數量選取: Nthreads = Nepu * Ucpu * ( 1 + W/C) 即 cpu數量 * 目標Cpu使用率 *(1 + 等待時間與計算時間比)

      分而治之:Fork/Join框架

      ForkJoinPool.submit(ForkJoinTask) 提交任務 task.fork() 執行結束後 使用 task.join收集結果

 3. JDK併發容器

     1. 併發集合

         ConcurrenHashMap

         CopyOnWriteArrayList

         ConcurrentLinkedQueue

         BlockingQueue 

         ConcurrentSkipListMap

    2. 高效讀寫隊列:深度剖析 ConcurentLinkedQueue

        主要通過CAS(比較交換)操作和對head及tail的算法實現高效的讀寫

    3. 高效讀取: 不變模式下的CopyOnWriteArrayList

        任何讀取操作沒有鎖相關操作,但是寫入時候.會加鎖,複製原來的集合寫一個新集合後替換老集合.

    4. 數據共享通道: BlockingQueue

        前面說過其take和put的通過兩個condition裏相互通知實現阻塞.

    5.隨機數據結構:跳錶(SkipList)

       維護多層鏈表,鏈表分層,通過空間換時間的方法來實現高速的查找.

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章