從classloader的變動提及

classloader從1.6到1.7總體分紅了兩個版本。重點區別就是並行類加載。java

1.6版本

protected synchronized Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
		……
        return c;
    }

1.6版本加了一個方法鎖。redis

1.7版本

private final ConcurrentHashMap parallelLockMap;
  
    protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
	        ……
            return c;
        }
    }

    protected Object getClassLoadingLock(String className) {
        Object lock = this;
        if (parallelLockMap != null) {
            Object newLock = new Object();
            lock = parallelLockMap.putIfAbsent(className, newLock);
            if (lock == null) {
                lock = newLock;
            }
        }
        return lock;
    }

1.7以後就是用了兩種模式getClassLoadingLock方法中,咱們能夠看出有兩種模式,一種是parallelLockMap爲空,鎖的對象是classloader自己,另一種是parallelLockMap不爲null。這裏會根據classname去獲取鎖,若是有返回的object不爲null。說明已經有class使用過了,若是爲null,就把新建的object當作鎖,達到了一個classname一個鎖的效果。算法

classloader加鎖的緣由

有不少classloader的例子直接複寫了loadClass可是沒有加鎖,只有讀取文件加載的過程,這種classloader都是特定場合使用的。並不具有通用性。衆所周知的一個規則,一個classloader不能加載相同類的字節碼,第二次加載就會在defineclass的時候報錯。
場景1
不一樣的線程能夠是相同的classloader,兩個線程的都是A classloader加載的,當裏面的有個方法裏都有B類時,兩個線程都會觸發A加載B類
場景2
雙親委託的狀況,A loader是B loader的parent。A能加載到C類。B loader加載c的時候委託給A,A也在同時加載C。此時觸發了兩次A加載C。數據庫

鎖分離的好處

鎖分離加快了併發,這個是顯而易見的。還有一個好處是減小了死鎖。在編寫javaagent的時候,只要在transform加點鎖,特別容易和classloader還有類初始化時候的鎖形成死鎖。基本死鎖的場景都在1.6。數組

鎖分離的案例

jdk中鎖分離的實現特別多緩存

讀寫分離

雙鎖讀寫分離
LinkedBlockingQueue有兩把鎖takeLock和putLock。 因爲隊列的特性——FIFO。在寫入的時候,競爭takeLock。讀取的時候競爭putLock。以此達到同事讀寫的增長吞吐量的目的。
副本機制讀寫分離
副本機制讀寫分離的典型就是copyonwrite。 CopyOnWriteArrayList。只有一把lock。可是使用的是數組存儲。用volatile修飾。寫入的時候獲取鎖,先用一個新的數組把舊的數據拷貝過來,而後把要加入的數據放入新數組中。最後替換 volatile的引用。讀取的時候就直接獲取volatile的數組。 這樣讀取的時候只是那一刻的副本,一旦開始遍歷,直到結束都不會有新的數據加入了。併發

寫寫分離

寫寫分離的場景是鎖細化。classloader的改進算是寫寫分離的狀況。典型的場景就是ConcurrentHashMap。ConcurrentHashMap的每一個槽位一把鎖,當沒有hash衝突的時候,元素的寫的過程是並行的。this

集羣鎖分離

集羣的鎖分離的場景咱們也用到的特別多。主要目的是提供併發。線程

  1. kafka 消費(讀寫分離)。kafka寫log,達到必定限制就會開啓新的文件,消費的時候,從舊的開始,就會從已經寫好的開始讀取。這種狀況下,讀文和寫的文件是兩個不一樣的文件。
  2. kafka topic分區。(寫寫分離)。kafka寫入根據分區算法。分別寫入不一樣的partition。相似的還有分庫,分表。只要是水平擴展的基本都是寫寫分離的。
  3. 主從機制(副本機制讀寫分離)。數據庫使用主備方案,而且備份庫只提供讀取操做。至於新入的數據的空缺,通常由redis等緩存彌補。
相關文章
相關標籤/搜索