资讯专栏INFORMATION COLUMN

JAVA 7+ 实现自动锁(AutoLock)

Songlcy / 1241人阅读

摘要:了解自动锁很早就受不了锁的机制了每次都需要在去解锁不仅代码不美观而且很麻烦我想能不能实现加锁之后自动解锁如果是可以利用析构函数实现但就想了想好像可以利用的特性对象只需要实现接口实现自动锁我了解如何利用特性写一个自动锁那么下面我们开始真正

了解自动锁

很早就受不了 java 锁的机制了,每次都需要在 finally 去解锁, 不仅代码不美观,而且很麻烦

我想能不能实现加锁之后自动解锁, 如果是C++ 可以利用析构函数实现, 但java就.......

想了想好像可以利用java7 的 try-with-resource 特性, 对象只需要实现 AutoCloseable 接口

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 抽象接口对象

// 自动锁实现类
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....
        }
    }
}

至此我们就实现了,我们假设的常用场景

更高级的用法

如果我要更细粒度的锁, 不是在对象的成员中存在锁对象,怎么办.
我写一个方法, 希望可以帮助大家, 抛砖引玉, 如果可以提供更好的方式请求留言

/**
 * Description: TestLock
 * Created by: IcerLeer
 * Created on: 2017-08-31 17:42
 */
public class LockUtils
{
    // 自动锁缓存队列, 实现不可重入
    private static ConcurrentHashMap 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);
    }
}

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70306.html

相关文章

  • [学习笔记-Java集合-7] Map - ConcurrentHashMap 源码分析(一)

    摘要:简介是的线程安全版本,内部也是使用数组链表红黑树的结构来存储元素。相比于同样线程安全的来说,效率等各方面都有极大地提高。中的关键字,内部实现为监视器锁,主要是通过对象监视器在对象头中的字段来表明的。 简介 ConcurrentHashMap是HashMap的线程安全版本,内部也是使用(数组 + 链表 + 红黑树)的结构来存储元素。 相比于同样线程安全的HashTable来说,效率等各方...

    SoapEye 评论0 收藏0
  • 并发编程导论

    摘要:并发编程导论是对于分布式计算并发编程系列的总结与归纳。并发编程导论随着硬件性能的迅猛发展与大数据时代的来临,并发编程日益成为编程中不可忽略的重要组成部分。并发编程复兴的主要驱动力来自于所谓的多核危机。 并发编程导论是对于分布式计算-并发编程 https://url.wx-coder.cn/Yagu8 系列的总结与归纳。欢迎关注公众号:某熊的技术之路。 showImg(https://...

    GeekQiaQia 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<