鎖之編程細節

前言

關於Java鎖細節的博客,蠻受讀者歡迎的。也有許多不足,好比排版,一些細節等。Java鎖細節與鎖之編程細節講述鎖的兩個不一樣方面,因此分開寫。Java鎖細節是講述每種鎖的細節,把鎖當作人的話,講述的是男人,女人,大人,小孩的細節。鎖之編程細節講述的如高性能的使用鎖。如同讓人怎麼跑得塊而已。java

大綱

編程細節以下:算法

  1. 鎖粗化
  2. 鎖細化
  3. 保證public方法線程安全
  4. 分段鎖

主體

關於鎖粗化與鎖細化,在不少關於java優化的書籍都會講解。好比java併發編程(是老胡併發與鎖的啓蒙書)等等。一些讀者在讀Java鎖細節說沒有講解鎖粗化。在你們的要求,老胡只能厚着麪皮寫下本博客了。編程

你們是否以爲十分繞口,鎖粗化,鎖細化在名詞上是兩個對立的。爲何都是優化的方法了?其實能夠想象成長跑,短跑。就行了。api

鎖粗化

  1. 把屢次的鎖合併成一個鎖,減小鎖消耗,提高執行性能
  2. 在高併發的狀況下,減小鎖競爭。

receiveIntegerNoLock 方法調用了兩個聲明synchronized的方法。數組

public  IntegeralInfo receiveIntegerNoLock(Integer addIntegeral) {
	    addIntegeral(addIntegeral);
	    addReceiveNum();
	    return this;
	}

	/**
	 * 增長積分
	 * 
	 * @param addIntegeral
	 */
	public synchronized void addIntegeral(Integer addIntegeral) {
	    this.integeralValue += addIntegeral;
	}

	/**
	 * 增長簽到次數
	 */
	public synchronized void addReceiveNum() {
	    this.receiveNum++;
	}

新的receiveInteger方法聲明瞭synchronized。值使用了一個鎖安全

public synchronized IntegeralInfo receiveInteger(Integer addIntegeral) {
	    this.integeralValue += addIntegeral;
	    this.receiveNum++;
	    return this;
}

鎖細化

  1. 只對須要數據安全的操做上鎖。減小鎖佔用時間。從而提高併發性能
  2. 使用。vm會對進行優化。鎖範圍爲少,優化越好

需求,經過連續簽到的天數,計算當次簽到應獲得多少積分,把計算出的積分增長到用戶積分上,並計算除等級。併發

分析以下高併發

  1. 須要經過連續簽到天數,計算當次簽到應獲得多少積分
  2. 把計算出的積分增長到用戶積分上
  3. 並計算除等級
案例
public synchronized void continuityReceiveIntegeralAlsoGradeSynchronized(Integer continuityDate) {
	    // 經過天數計算,應該得到多少積分
	    int addIntegeral = calculationSignIntegeral(continuityDate);
	    // 添加積分
	    this.integeralValue += addIntegeral;
	    // 計算等級
	    gradeCalculation();
	}
		public int calculationSignIntegeral(Integer continuityDate) {
	    return continuityDate/1;
	}
	/**
	 * 等級計算
	 */
	private void gradeCalculation() {

	}

最簡單的實現,沒有進行任何的優化。三個操做的代碼放到一個方法裏面。觀察calculationSignIntegeral方法會發現,只是進行數據計算,是一個安全的方法,能夠不用上鎖。gradeCalculation方法在必定程度上也是安全的方法,未實現。這個需求有點複雜,不知道那個大神,能夠分析出來,並實現。性能

優化以後的是
public void continuityReceiveIntegeralAlsoGrade(Integer continuityDate) {
			// 經過天數計算,應該得到多少積分
			int addIntegeral = calculationSignIntegeral(continuityDate);
			// 添加積分
			synchronized (this) {
					this.integeralValue += addIntegeral;
			}
			// 計算等級
			gradeCalculation();
	}

只對須要上鎖的計算出的積分增長到用戶積分上操做進行上鎖,減小的上鎖範圍。縮短持有鎖的時間,從而提升併發性能學習

public都是線程安全

java api裏面的類,個個都寫得十分優秀。是學習,深刻,理解基礎技術的優質的代碼。解讀java.util.Hashtable的源碼,從而理解public都是線程安全,而非public方法都是線程不安全的。當你看完java.util.Hashtable源碼會發現,全部的public都是線程安全,而非public方法都是線程不安全的。

public都是線程安全,而非public方法都是線程不安全的。這種設計有一下特性

  1. 一種優秀的編碼規範,方法層次十分明顯,強大的可讀性。減小開發成本,維護成本,理解成本,容易定位問題。
  2. 全部public方法的實現只能爲鎖粗化。
  3. public方法內沒有具體的實現,只負責調用private方法。private負責具體的實現。這是一種開閉原則的具體實現。

開閉原則(OCP)是面向對象設計中「可複用設計」的基石,是面向對象設計中最重要的原則之一,其它不少的設計原則都是實現開閉原則的一種手段。對於擴展是開放的,對於修改是關閉的,這意味着模塊的行爲是能夠擴展的

分段鎖

按照算法計算出的結果或者數據特性進行分類,分類中的每一個類型都有一把鎖。能夠減小鎖爭奪,更高並行度

關於分段鎖最簡單的實現仍是在java api中,jdk6的ConcurrentHashMap。 ConcurrentHashMap經過hash算法獲得key的hash值,在與數組長度求餘,餘數是數組下標。下標就是分類的類型 下面連接是一個大神寫的關於jdk6的ConcurrentHashMap源碼解讀,寫得有點亂,可是解讀得十分詳細。請點擊

完整代碼

public class LockUser {

    static class IntegeralInfo {
	// 用戶積分
	private Integer integeralValue;

	// 經驗值
	private Integer experienceValue;

	// 簽到
	private Integer receiveNum;

	// 等級
	private Integer grade;

	/**
	 * 添加積分,同時增長簽到次數
	 * 
	 * @param addIntegeral
	 *            須要添加的積分
	 * @return
	 */
	public synchronized IntegeralInfo receiveInteger(Integer addIntegeral) {
	    this.integeralValue += addIntegeral;
	    this.receiveNum++;
	    return this;
	}
	
	public  IntegeralInfo receiveIntegerNoLock(Integer addIntegeral) {
	    addIntegeral(addIntegeral);
	    addReceiveNum();
	    return this;
	}

	/**
	 * 增長積分
	 * 
	 * @param addIntegeral
	 */
	public synchronized void addIntegeral(Integer addIntegeral) {
	    this.integeralValue += addIntegeral;
	}

	/**
	 * 增長簽到次數
	 */
	public synchronized void addReceiveNum() {
	    this.receiveNum++;
	}

	public synchronized void continuityReceiveIntegeralAlsoGradeSynchronized(Integer continuityDate) {
	    // 經過天數計算,應該得到多少積分
	    int addIntegeral = calculationSignIntegeral(continuityDate);
	    // 添加積分
	    this.integeralValue += addIntegeral;
	    // 計算等級
	    gradeCalculation();
	}

	public void continuityReceiveIntegeralAlsoGrade(Integer continuityDate) {
	    // 經過天數計算,應該得到多少積分
	    int addIntegeral = calculationSignIntegeral(continuityDate);
	    // 添加積分
	    synchronized (this) {
		this.integeralValue += addIntegeral;
	    }
	    // 計算等級
	    gradeCalculation();
	}

	public int calculationSignIntegeral(Integer continuityDate) {
	    return 1;
	}

	/**
	 * 等級計算
	 */
	private void gradeCalculation() {

	}
    }
}
相關文章
相關標籤/搜索