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