• 如何基于 String 实现同步锁?


    如何基于String实现同步锁?

    在某些时候,我们可能想基于字符串做一些事情,比如:针对同一用户的并发同步操作,使用锁字符串的方式实现比较合理。

    因为只有在相同字符串的情况下,并发操作才是不被允许的。而如果我们不分青红皂白直接全部加锁,那么整体性能就下降得厉害了。

    因为String的多样性,看起来string锁是天然比分段锁之类的高级锁更有优势呢。

    因为String 类型的变量赋值是这样的: String a = "hello world."; 所有往往会有个错误的映象,String对象就是不可变的。

    额,关于这个问题的争论咱们就不细说了,总之, "a" != "a" 是有可能成立的。

    另外,针对上锁这件事,我们都知道,锁是要针对同一个对象,才会有意义。所以,粗略的,我们可以这样使用字符串锁:

    public void method1() {  
        String str1 = "a";  
        synchronized (str1) {  
            // do sync a things...  
        }  
    }  

    public void method2() {  
        String str2 = "a";  
        synchronized (str2) {  
            // do sync b things...  
        }  
    }  

    乍一看,这的确很方便简单。但是,前面说了, "a" 是可能不等于 "a" 的(这是大部分情况,只有当String被存储在常量池中时值相同的String变量才相等)。5个刁钻的String面试题,推荐大家看下。

    所以,我们可以稍微优化下:

    public void method3() {  
        String str1 = "a";  
        synchronized (str1.intern()) {  
            // do sync a things...  
        }  
    }  

    public void method4() {  
        String str2 = "a";  
        synchronized (str2.intern()) {  
            // do sync b things...  
        }  
    }  

    看起来还是很方便简单的,其原理就是把String对象放到常量池中。但是会有个问题,这些常量池的数据如何清理呢?

    不管怎么样,我们是不是可以自己去基于String实现一个锁呢?

    肯定是可以的了!直接上代码!

    如何基于 String 实现同步锁?

     

    如何基于 String 实现同步锁?

     

    如何基于 String 实现同步锁?

     

    使用时,只需传入 lockKey 即可。 这样做有什么好处吗?

    1. 使用ConcurrentHashMap实现锁获取,性能还是不错的;
    2. 每个字符串对应一个锁,使用完成后就删除,不会导致内存溢出问题;
    3. 可以作为一个外部工具使用,业务代码接入方便,无需像 synchronized 一样,需要整段代码包裹起来;
    4. 本文只是想展示实现 String 锁,此锁并不适用于分布式场景下的并发处理;

    扩展: 如果不使用 String 做锁,如何保证大并发前提下的小概率并发场景的线程安全?

    我们知道 CAS 的效率是比较高的,我们可以使用原子类来进行CAS的操作。

    比如,我们添加一状态字段, 操作此字段以保证线程安全:

    如何基于 String 实现同步锁?

     

    实际测试下来,CAS 性能是要比 synchronized 之类的锁性能要好的。

    当然,我们这里针对的并发数都是极少的,我们只是想要保证这极少情况下的线程安全性。所以,其实也还好。

  • 相关阅读:
    Creating A Simple Web Server With Golang
    go-import下划线的作用
    golang 查询数据库操作
    golang 跨平台编译——go 在windows上编译Linux平台的程序(Cross Compilation from Windows to Linux/Ubuntu)
    golang convert integer to float number
    AngularJS $q 和 $q.all 单个数据源和多个数据源合并(promise的说明)
    golang中关闭http server
    如何快速掌握plc或工控机与其他设备的modbus通讯协议?包括格式与实际过程 RT,本人从事工控行业多年,对于PLC与触摸屏也算比较熟悉,唯独对这个通讯协议比较难理解,请教高人指导,从什么地方开始下手,或者是说如何正确理解报文格式或正确写入
    网络适配器是啥
    路由器与交换机
  • 原文地址:https://www.cnblogs.com/CQqfjy/p/12710346.html
Copyright © 2020-2023  润新知