JAVA 7+ 實現自動鎖(AutoLock)

  • 瞭解自動鎖

很早就受不了 java 鎖的機制了,每次都須要在 finally 去解鎖, 不只代碼不美觀,並且很麻煩java

我想能不能實現加鎖以後自動解鎖, 若是是C++ 能夠利用析構函數實現, 但java就.......緩存

想了想好像能夠利用java7 的 try-with-resource 特性, 對象只須要實現 AutoCloseable 接口ide

class AutoLock implements AutoCloseable
{
    // other function start
    
    // ........
    
    // other function end

    // I like this feature
    @Override
    public void close() throws Exception
    {
        unLock();
    }
}
  • 實現自動鎖

我瞭解如何利用java特性寫一個自動鎖那麼, 下面咱們開始真正的實現函數

// 自動鎖實現類
public static class AutoLock implements AutoCloseable
{
    // 重入鎖對象
    private ReentrantLock reentrantLock = new ReentrantLock();

    /**
     * 自動鎖 加鎖
     * @return 返回自動鎖自己
     */
    public AutoLock lock()
    {
        // 加鎖
        reentrantLock.lock();
        return this;
    }

    public static AutoLock getAutoLock()
    {
        return new AutoLock().lock();
    }

    /**
     * 自動鎖解鎖
     * @return 返回自動鎖自己
     */
    private AutoLock unLock()
    {
        // 解鎖
        if (null != reentrantLock && reentrantLock.isLocked())
        {
            reentrantLock.unlock();           
        }
        return this;
    }

    @Override
    public void close() throws Exception
    {
        unLock();
    }
}
// 簡單, 調用示例

public void testAutoLock() throws Exception
{
    try(AutoLock autoLock = new AutoLock())
    {
        autoLock.lock()
        // do some thing.....
    }
    
    // 不用再解鎖了, 不用再解鎖了, 不用再解鎖了!!!
}
// 更方便的調用示例

public void testAutoLock() throws Exception
{
    // 使用靜態方法
    try(AutoLock autoLock = AutoLock.getAutoLock())
    {
        // do some thing.....
    }
    
    // 不用再解鎖了, 不用再解鎖了, 不用再解鎖了!!!
}
  • 自動鎖的使用場景

前面兩種調用方式, 只是打個比方, 可是不少時候,咱們的需求並非 每次都須要 new ReentrantLock(), 這樣並無什麼N用的, 由於每次新的"重入鎖"實例, 起不到防止重入的目的, 那咱們改變一下方式, 咱們作兩個地方的改變, 咱們修改reentrantLock 成員不作初始化new, 而是經過參數傳入Lock 抽象接口對象this

// 自動鎖實現類
public class AutoLock implements AutoCloseable
{
    // *重入鎖對象 (改變1)*
    private Lock autoLock = null

    // *重寫構造函數(改變2)*
    private AutoLock(Lock autoLock)
    {
        this.autoLock = autoLock;
    }

    /**
     * 自動鎖 加鎖
     * @return 返回自動鎖自己
     */
    public AutoLock lock()
    {
        // *加鎖(改變3)*
        if (null != reentrantLock)
        {
            reentrantLock.lock();
        }
        return this;
    }

    // *獲取自動鎖對象 (改變4)*
    public static AutoLock getAutoLock(Lock autoLock)
    {
        return new AutoLock(autoLock).lock();
    }

    /**
     * 自動鎖解鎖
     * @return 返回自動鎖自己
     */
    private AutoLock unLock()
    {
        // 解鎖
        if (null != autoLock)
        {
            autoLock.unlock();
        }
        return this;
    }

    @Override
    public void close() throws Exception
    {
        unLock();
    }
}

至於爲何傳入的是 Lock 抽象接口, 由於很所時候,咱們可能自定義一個鎖對象, 或者之後JDK可能提供的其餘鎖, 咱們來看看調用示例吧線程

public class TestService()
{
    private Lock reentrantLock = new ReentrantLock();
    
    // 假設線程A調用此方法
    pubilc void testAutoLockA() throws Exception
    {
        try(AutoLock autoLock = AutoLock.getAutoLock(reentrantLock))
        {
            // do some thing....
        }
    }
    
    // 假設線程B調用此方法
    public void testAutoKLockB() throws Exception
    {
        try(AutoLock autoLock = AutoLock.getAutoLock(reentrantLock))
        {
            // do some thing....
        }
    }
}

至此咱們就實現了,咱們假設的經常使用場景code

  • 更高級的用法

若是我要更細粒度的鎖, 不是在對象的成員中存在鎖對象,怎麼辦.
我寫一個方法, 但願能夠幫助你們, 拋磚引玉, 若是能夠提供更好的方式請求留言對象

/**
 * Description: TestLock
 * Created by: IcerLeer
 * Created on: 2017-08-31 17:42
 */
public class LockUtils
{
    // 自動鎖緩存隊列, 實現不可重入
    private static ConcurrentHashMap<String, AutoLock> lockMap = new ConcurrentHashMap<>();

    /**
     * 獲取自動鎖
     * @param strKey 自動鎖關鍵字
     * @return 返回自動鎖對象
     */
    public static AutoLock getAutoLock(String strKey)
    {
        synchronized (strKey.intern())
        {
            return lockMap.computeIfAbsent(strKey, key -> new AutoLock(strKey)).lock();
        }
    }

    /**
     * 移除自動鎖
     * @param strKey 自動鎖關鍵字
     */
    private static void removeAutoLock(String strKey)
    {
        lockMap.remove(strKey);
    }

    /**
     * 自動鎖
     */
    public static class AutoLock implements AutoCloseable
    {
        // 鎖的關鍵字
        private String lockKey = "";
        // 事務鎖對象
        private ReentrantLock reentrantLock = new ReentrantLock();
        // 引用計數
        private int refNumber = 0;

        // 初始化構造函數
        public AutoLock(String strKey)
        {
            if (StringUtils.isNotBlank(strKey))
            {
                lockKey = strKey;
            }
        }

        /**
         * 自動鎖 加鎖
         * @return 返回自動鎖自己
         */
        private AutoLock lock()
        {
            // 增長引用次數
            refNumber++;
            // 加鎖
            reentrantLock.lock();
            return this;
        }

        /**
         * 自動鎖解鎖
         * @return 返回自動鎖自己
         */
        private AutoLock unLock()
        {
            // 解鎖
            if (null != reentrantLock && reentrantLock.isLocked())
            {
                reentrantLock.unlock();
                // 判斷是否應該把自動鎖移除隊列
                synchronized (lockKey.intern())
                {
                    // 減小引用次數
                    refNumber--;
                    // 若是引用計數
                    if (0 == refNumber)
                    {
                        removeAutoLock(lockKey);
                    }
                }
            }
            return this;
        }

        @Override
        public void close() throws Exception
        {
            unLock();
        }

    }
}

固然少不了調用示例接口

private void testAutoLockA() throws Exception
{
    /// "Test" 爲鎖的關鍵字, 相同的關鍵字實現不可重入鎖
    try(LockUtils.AutoLock autoLock = LockUtils.getAutoLock("Test"))
    {
        // do some thing
        sleep(10);
    }
}

private void testAutoLockB() throws Exception
{
    /// "Test" 爲鎖的關鍵字, 相同的關鍵字實現不可重入鎖
    try(LockUtils.AutoLock autoLock = LockUtils.getAutoLock("Test"))
    {
        // do some thing
        sleep(10);
    }
}
相關文章
相關標籤/搜索