1. 程式人生 > >JUC介紹 以及JUC中的鎖框架

JUC介紹 以及JUC中的鎖框架

Java JUC 簡介
在Java 5.0 提供了java.util.concurrent(簡稱JUC )包,在此包中增加了在併發程式設計中很常用的實用工具類。
用於定義類似於執行緒的自定義子系統,包括執行緒池、非同步IO 和輕量級任務框架。提供可調的、靈活的執行緒池。還提供了設計用於多執行緒上下文中的Collection 實現(JUC集合)

鎖結構:

在這裡插入圖片描述
下面這個圖更方便理解:
在這裡插入圖片描述

在本篇文章之前,我們已經對併發機制中出現的很多的常見知識點進行了總結,今天我們來回顧一下有哪些是JUC包中的。

1.volatile關鍵字:
當多個執行緒共享某一個變數的時候,可以實現記憶體可見性(記憶體中的資料可見),相較於synchronized是一個輕量級的同步機制。但是volatile不保證原子性和有序性還有一個互斥性。
2.JUC中提供的原子變數類:


包括AtomicInteger等Atomic家族類。檢視原始碼即可知道,其中的變數都是用volatile修飾保證記憶體可見性,通過CAS演算法保證資料的原子性。
CAS:三個引數:V( 記憶體中的值) A 預估值 B更新值 當且僅當V==A時,將B更新值賦給V,否則不做任何操作。
3.1ConcurrentHashMap鎖分段機制
a. java5.0在JUC包中提供了多種併發容器來改進同步容器的效能;、
b. concurrentHashMap同步容器是java5增加的一個執行緒安全的雜湊表,對多執行緒的操作介於HashMap和HashTable之間,內部採用了“鎖分段”機制代替了HashTable的獨佔鎖,進而提高效能。
c. 此包還提供了設計用於多執行緒上下文中的Collection實現:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList和CopyOnWriteArraySet。當期望許多執行緒訪問一個給定collection時, ConcurrentHashMap通常優於同步的HashMap,ConcurrentSkipListMap通常優於同步的TreeMap.當期望的讀數和遍歷遠遠大於列表的更新數時,CopyOnWriteArrList優於同步的ArrayList。
3.2CountDownLatch閉鎖操作

 CountDownLatch:閉鎖,在完成某些運算時,只有其他所有的執行緒的運算全部完成,當前運算才算執行。
 CountDownLatch 一個同步輔助類,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。
閉鎖可以延遲執行緒的進度直到其達到終止狀態,閉鎖可以用來確保某些活動直到其他活動都完成才繼續執行:
     確保某個計算在其需要的所有資源都被初始化之後才繼續執行
    確保某個服務在其依賴的所有其他服務都已經啟動之後才啟動
    等待直到某個操作所有參與者都準備就緒在繼續執行

 以下程式碼是用通過閉鎖計算10執行緒執行的時間
4.執行緒池
執行緒池:提供了一個執行緒佇列,佇列中儲存著所有等待狀態的執行緒
,避免了建立與銷燬額外開銷,提高了響應的速度。
Java.util.concurrent.Executor: 負責執行緒的使用與排程的根介面;
執行緒池的體系結構:

  • java.util.concurrent.Executor : 負責執行緒的使用與排程的根介面
  •  |--**ExecutorService 子介面: 執行緒池的主要介面
    
  •      |--ThreadPoolExecutor 執行緒池的實現類
    
  •      |--ScheduledExecutorService 子介面:負責執行緒的排程
    
  •          |--ScheduledThreadPoolExecutor :繼承 ThreadPoolExecutor, 實現 ScheduledExecutorService
    

工具類 : Executors

  • ExecutorService newFixedThreadPool() : 建立固定大小的執行緒池
  • ExecutorService newCachedThreadPool() : 快取執行緒池,執行緒池的數量不固定,可以根據需求自動的更改數量。
  • ExecutorService newSingleThreadExecutor() : 建立單個執行緒池。執行緒池中只有一個執行緒
  • ScheduledExecutorService newScheduledThreadPool() : 建立固定大小的執行緒,可以延遲或定時的執行任務。
    */
    5.Lock:Lock同步鎖
      用於解決多執行緒安全問題的方式。
      synchronized:隱式鎖,同步程式碼塊、同步方法。
      Jdk1.5後:同步鎖Lock,是一種顯式鎖 ,需要通過lock()方式上鎖,必須通過unlock方法進行釋放鎖;
    Lock實現執行緒等待喚醒機制
    6.實現Callable介面:
    建立執行執行緒的方式三:實現Callble介面。相較於實現Runnable介面的方式,方法可以有返回值,並且可以丟擲異常
public class TestCallable {

    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        // 1.執行Callable方式,需要FutureTask實現類的支援,用於接收運算結果。
        FutureTask<Integer> result = new FutureTask<Integer>(td);
        new Thread(result).start();

        // 2.接收執行緒運算後的結果
        try {
           Integer sum =  result.get();
           System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class ThreadDemo implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i = 0; i<=100;i++){
            System.out.println(i);
            sum+=i;
        }
        return sum;
    }
}

7.Condition 控制執行緒通訊
Condition 介面描述了可能會與鎖有關聯的條件變數
這些變數在用法上與使用Object.wait 訪問的隱式監視器類似,但提供了更強大的功能。
需要特別指出的是,單個Lock 可能與多個Condition 物件關聯。
為了避免相容性問題,Condition 方法的名稱與對應的Object 版本中的不同。
在Condition 物件中,與wait、notify 和notifyAll 方法對應的分別是await、signal 和signalAll。
Condition 例項實質上被繫結到一個鎖上。要為特定Lock 例項獲得Condition 例項,請使用其newCondition() 方法。

/*
 * 生產者消費者案例:
 */
public class TestProductorAndConsumerForLock {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Productor pro = new Productor(clerk);
        Consumer con = new Consumer(clerk);

        new Thread(pro, "生產者 A").start();
        new Thread(con, "消費者 B").start();

//       new Thread(pro, "生產者 C").start();
//       new Thread(con, "消費者 D").start();
    }

}

class Clerk {
    private int product = 0;

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    // 進貨
    public void get() {
        lock.lock();

        try {
            if (product >= 1) { // 為了避免虛假喚醒,應該總是使用在迴圈中。
                System.out.println("產品已滿!");

                try {
                    condition.await();
                } catch (InterruptedException e) {
                }

            }
            System.out.println(Thread.currentThread().getName() + " : "
                    + ++product);

            condition.signalAll();
        } finally {
            lock.unlock();
        }

    }

    // 賣貨
    public void sale() {
        lock.lock();

        try {
            if (product <= 0) {
                System.out.println("缺貨!");

                try {
                    condition.await();
                } catch (InterruptedException e) {
                }
            }

            System.out.println(Thread.currentThread().getName() + " : "
                    + --product);

            condition.signalAll();

        } finally {
            lock.unlock();
        }
    }
}

// 生產者
class Productor implements Runnable {

    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            clerk.get();
        }
    }
}

// 消費者
class Consumer implements Runnable {

    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }

}

讀寫鎖
執行緒按序交替
ForkJoinPool分支/合併框架工作竊取

?
Fork Join與執行緒池的區別
在這裡插入圖片描述

JUC篇具體介紹:https://blog.csdn.net/cx8122389/article/details/70049425

java多執行緒各個點的詳細介紹 有43篇呢
http://www.cnblogs.com/skywang12345/p/java_threads_category.html