JUC基礎知識篇

java併發實戰 -- JUC線程高級

##1.volatile關鍵字-內存可見性 內存可見性問題是,當多個線程操做共享數據時,彼此不可見。<br/> volatile關鍵字:當多個線程操做共享數據時,能夠保存內存中的數據是可見的。相較於synchronized是一種較爲輕量級的同步策略。<br> 注意:<br>html

  1. volatile 不具有互斥性<br>
  2. volatile不能保證變量的原子性

##2.原子變量-CAS算法 ###i++的原子性問題: i++的操做實際上分爲三個步驟"讀-改-寫"。 1 int i = 10; 2 i = i++;//10java

1 int temp = i;
2 i = i + 1;
3 i = temp;

###原子變量:jdk1.5後java.util.concurrent.atomic包下提供了經常使用的原子變量: 1.volatile保證內存可見性<br/> 2.CAS(Compare-And - Swap)算法保證數據的原子性<br/>  CAS 算法是硬件對於併發操做共享數據的支持<br/>  CAS 包含了三個操做數:<br/>   內存值V<br/>   預估值A<br/>   更新值B<br/> 當且僅當 V == A時,V = B,不然,將不作任何操做。算法

##3.ConcurrentHashMap鎖分段機制 java5.0 在java.util.concurrent包中提供了多種併發容器類來改進同步容器的性能。<br> ConcurrentHashMap 同步容器類是java5增長的一個線程安全的哈希表。內部採用「鎖分段」機制替代Hashtable的獨佔鎖,進而提升性能。<br/> 此包還提供了設計用於多線程上下文中的Collection實現: ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList、CopyOnWriteArraySet。當指望許多線程訪問一個給定collection時,ConcurrentHashMap 一般優於同步的HashMap,ConcurrentSkipListMap一般優於同步的TreeMap。當指望的讀數和遍歷遠遠大於列表的更新數時,CopyOnWriteArrayList優於同步的ArrayList。緩存

##4.CountDownLatch閉鎖 閉鎖:一個同步輔助類,在完成某些運算時,只有其餘全部線程的運算所有完成,當前運算才繼續執行安全

##5.實現Callable接口 **java5.0以後提供了一個新的建立執行線程的方式:Callable接口。 Callable須要依賴FutureTask,FutureTask也能夠用做閉鎖。 Callable與Runnable的異同點<br>多線程

  1. 二者都是爲那些其實例可能被另外一個線程執行的類設計的<br>
  2. Runnable不會返回結果,而且沒法拋出通過檢查的異常<br>**

##6.Lock同步鎖 用於解決多線程安全問題的方式:<br> synchronized:<br>併發

  1. 同步代碼塊<br>
  2. 同步方法<br> jdk1.5後<br>
  3. 同步鎖Lock<br> 注意:這是一個顯示鎖,須要經過lock()方法上鎖,必須經過unlock()方法進行釋放鎖。<br> ReentranLock實現了Lock接口,並提供了與synchronized相同的互斥性和內存可見性。但相較於synchronized提供了更高的處理鎖的靈活性。
    ##7.Condition控制線程通訊 Cndition接口描述了可能會與鎖有關聯的條件變量。這些變量在用法上與使用Object.wait訪問的隱式監視器相似,但提供了更強大的功能。須要特別指出的是,單個Lock可能與多個Condition對象關聯。<br> 在condition對象中,方法分別爲await、signal、signalAll。(與咱們在操做系統中線程同步章節所學的十分類似。)<br> Condition實例實質上被綁定到一個鎖上。要爲特定Lock實例得到Condition實例,請使用newCondition()方法。 ##8.線程八鎖 因爲內容太多,只能寫個總結。<br> 線程八鎖的關鍵<br> ①非靜態方法的鎖默認爲實例對象自己,靜態方法的鎖爲對應的類對象自己<br> ②某一個時刻內,只能有一個線程持有鎖,不管幾個方法。

##9.線程按序交替 編寫一個程序,開啓 3 個線程,這三個線程的 ID 分別爲 A、B、C,每一個線程將本身的 ID 在屏幕上打印 10 遍,要求輸出的結果必須按順序顯示框架

public class TestABCAlternate {

public static void main(String[] args) {
	AlternateDemo ad = new AlternateDemo();
	
	new Thread(new Runnable() {
		@Override
		public void run() {
			
			for (int i = 1; i <= 20; i++) {
				ad.loopA(i);
			}
			
		}
	}, "A").start();
	
	new Thread(new Runnable() {
		@Override
		public void run() {
			
			for (int i = 1; i <= 20; i++) {
				ad.loopB(i);
			}
			
		}
	}, "B").start();
	
	new Thread(new Runnable() {
		@Override
		public void run() {
			
			for (int i = 1; i <= 20; i++) {
				ad.loopC(i);
				
				System.out.println("-----------------------------------");
			}
			
		}
	}, "C").start();
	}

}

class AlternateDemo{

	private int number = 1; //當前正在執行線程的標記
	
	private Lock lock = new ReentrantLock();
	private Condition condition1 = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	private Condition condition3 = lock.newCondition();
	
	/**
	 * @param totalLoop : 循環第幾輪
	 */
	public void loopA(int totalLoop){
		lock.lock();
		
		try {
			//1. 判斷
			if(number != 1){
				condition1.await();
			}
			
			//2. 打印
			for (int i = 1; i <= 1; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
			}
			
			//3. 喚醒
			number = 2;
			condition2.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void loopB(int totalLoop){
		lock.lock();
		
		try {
			//1. 判斷
			if(number != 2){
				condition2.await();
			}
			
			//2. 打印
			for (int i = 1; i <= 1; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
			}
			
			//3. 喚醒
			number = 3;
			condition3.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}
	
	public void loopC(int totalLoop){
		lock.lock();
		
		try {
			//1. 判斷
			if(number != 3){
				condition3.await();
			}
			
			//2. 打印
			for (int i = 1; i <= 1; i++) {
				System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
			}
			
			//3. 喚醒
			number = 1;
			condition1.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
			}
		}
	}

##10.ReadWirteLock讀寫鎖 ReadWriteLock維護了一對相關的鎖,一個用於只讀操做,另外一個用於寫入操做。只要沒有Writer,讀取鎖能夠由多個reader線程同時保持。寫入鎖是獨佔的。<br> ReadWriteLock 讀取操做一般不會改變共享資源,但執行寫入操做時,必須獨佔方式來獲取鎖。ide

##11.線程池 第四種獲取線程的方法: 線程池,一個ExecutorService,它使用可能的幾個線程池之一執行每一個提交的任務,一般使用Executors工廠方法配置。<br/> 1、線程池:提供了一個線程隊列,隊列中保存着全部等待狀態的線程。避免了建立與銷燬額外開銷,提升了響應的速度。<br> 2、線程池的體系結構:<br> java.util.concurrent.Executor : 負責線程的使用與調度的根接口<br> |--ExecutorService 子接口: 線程池的主要接口<br> |--ThreadPoolExecutor 線程池的實現類<br> |--ScheduledExecutorService 子接口:負責線程的調度<br> |--ScheduledThreadPoolExecutor :繼承 ThreadPoolExecutor, 實現 ScheduledExecutorService<br> 3、工具類 : Executors <br> ExecutorService newFixedThreadPool() : 建立固定大小的線程池<br> ExecutorService newCachedThreadPool() : 緩存線程池,線程池的數量不固定,能夠根據需求自動的更改數<br> ExecutorService newSingleThreadExecutor() : 建立單個線程池。線程池中只有一個線程<br> ScheduledExecutorService newScheduledThreadPool() : 建立固定大小的線程,能夠延遲或定時的執行任務。 ##12.線程調度 一個ScheduledExecutorService,可安排在給定的延遲後運行或按期地執行命令。 ##13.ForkJoinPool 分支/合併框架 工做竊取 Fork/Join框架:就是在必要的狀況下,將一個大任務,進行拆分紅若干個小任務(拆到不可再拆時),再將一個個的小人物運算的結果進行join彙總。<br>工具

工做竊取 : 當執行新的任務時它能夠將其拆分分紅更小的任務執行,並將小任務加到線程隊列中,而後再從一個隨機線程的隊列中偷一個並把它放在本身的隊列中,而後再從一個隨機線程的隊列中偷一個並把它放在本身的隊列中。

原文出處:https://www.cnblogs.com/liben123/p/11082263.html

相關文章
相關標籤/搜索