如何基于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实现一个锁呢?

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

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

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

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

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

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

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

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

如何基于 String 实现同步锁?的更多相关文章

  1. 如何基于String实现同步锁?

    在某些时候,我们可能想基于字符串做一些事情,比如:针对同一用户的并发同步操作,使用锁字符串的方式实现比较合理.因为只有在相同字符串的情况下,并发操作才是不被允许的.而如果我们不分青红皂白直接全部加锁, ...

  2. 如何基于String实现锁?

    在某些时候,我们可能想基于字符串做一些事情,比如:针对同一用户的并发同步操作,使用锁字符串的方式实现比较合理.因为只有在相同字符串的情况下,并发操作才是不被允许的. 因为String 类型的变量赋值是 ...

  3. Java中String做为synchronized同步锁使用详解

    Java中使用String作同步锁 在Java中String是一种特殊的类型存在,在jdk中String在创建后是共享常量池的,即使在jdk1.8之后实现有所不同,但是功能还是差不多的. 借助这个特点 ...

  4. 同步锁Lock

    用于解决多线程安全问题有三种方式: 同步代码块(隐式锁,基于JVM) 同步方法(隐式锁,基于JVM) 同步锁(显式锁,jdk1.5后出现,相对于前两种方式,更加灵活) 下面通过一段程序来说明一下同步锁 ...

  5. java 多线程: Thread 并发访问-代码块同步synchronized {};String作为被锁的对象

    方法同步的弊端 方法同步的时候,如果一个方法需要线程安全控制的代码速度其实很快,但是还有其他的业务逻辑代码耗时非常长(比如网络请求),这样所有的线程就在这一块就等待着了,这样造成了极大的资源浪费如果并 ...

  6. 基于redis 实现分布式锁的方案

    在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题.如果在库存操作上,加锁就可以避免库存卖超的问题.分布式锁使分布式系统之间同步访问共享资源的一种方式 基于redis实现分布式锁 ...

  7. 基于 Redis 的分布式锁

    前言 分布式锁在分布式应用中应用广泛,想要搞懂一个新事物首先得了解它的由来,这样才能更加的理解甚至可以举一反三. 首先谈到分布式锁自然也就联想到分布式应用. 在我们将应用拆分为分布式应用之前的单机系统 ...

  8. 基于redis的分布式锁实现

    1.分布式锁介绍 在计算机系统中,锁作为一种控制并发的机制无处不在. 单机环境下,操作系统能够在进程或线程之间通过本地的锁来控制并发程序的行为.而在如今的大型复杂系统中,通常采用的是分布式架构提供服务 ...

  9. 基于ZooKeeper实现——分布式锁与实现

    引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...

随机推荐

  1. svn客户端访问失败,错误“请求的名称有效,但是找不到请求的类型”的解决

    1.问题描述:visualSVN客户端在其他机子访问出现以下问题(服务端装在我的电脑上,我本机客户端可以正常访问) 2. 原因分析:SVN客户端访问服务器需要输入URL地址,URL地址分为两种方式.一 ...

  2. PHP基础-PHP中的函数声明

    /* PHP的变量的范围* 局部变量: 在函数中声明的变量就是局部变量,只能在自己的函数内部使用.* 全局变量: 在函数外声明,在变量声明以后的,直到整个脚本结束前都可以使用,包括在函数中和{}中都可 ...

  3. 使用C#进行数据库增删改查ADO.NET(三)

    文章代码如下: class Program { static void Main (string[] args) { //连接数据库 string connString = "server= ...

  4. 二分查找确定lower_bound和upper_bound

    lower_bound当target存在时, 返回它出现的第一个位置,如果不存在,则返回这样一个下标i:在此处插入target后,序列仍然有序. 代码如下: int lower_bound(int* ...

  5. 黄衫女子,黄衫好.png

    正想着团队项目中数据该如何解析,就收到了来自软工课程组的一件小黄衫,真是意外之喜.详问其来源,竟是因结对项目做的"较好"而来,顿感受之有愧. 结对项目是两人对文件系统的一个小模拟, ...

  6. Java on Visual Studio Code的更新 – 2021年4月

    杨尧今 from Microsoft VS Code Java Team 欢迎来到这一期的VS Code Java更新.又是一个忙碌而富有成效的月份. Java调试器和Java测试扩展获得了新功能.在 ...

  7. 『动善时』JMeter基础 — 21、HTTP Cookie管理器的使用

    目录 1.在HTTP信息头管理器组件中添加Cookie信息 (1)测试计划内包含的元件 (2)请求取样器内容 (3)HTTP信息头管理器内容 (4)查看结果 2.使用HTTP Cookie管理器组件来 ...

  8. [bug] HDFS:DataXceiver error processing WRITE_BLOCK operation

    文件格式有误,导致读取错误,我的是把制表符敲成了空格

  9. [刷题] 300 Longest Increasing Subsequence

    要求 给定一个整数序列,求其中的最长上升子序列长度 子序列元素可不相邻 元素相等不算上升 一个序列可能有多个最长上升子序列,但最长的长度只有一个 思路 暴力解法:选择所有子序列进行判断((2^n)*n ...

  10. [Qt] 打包

    步骤: 1.release项目,生成exe文件 2.在命令行中使用windeployqt,将相关文件复制到exe文件所在文件夹 3.用Enigma Virtual Box打包所有文件 参考 https ...