java id 锁_java 多线程synchronized同步锁锁住相同用户Id
本文介绍使用java synchronized同步锁来实现对相同userId进行加锁
众所周知synchronized只能锁对象地址,而对于如下加锁是完全没有用的
public void test(Long userId) {
synchronized (userId) {//除了-127-128外其他的值都锁不住
// ...
}
}
原因就在于±127之外的都是new除来的Long(见源码Long.valueOf),地址值当然不一样了。
既然synchronized需要同一个对象,那我们将同一对象缓存下来不就得了。
private HashMapmMap = new HashMap<>();
public Long getLock(Long userId) {
if (!mMap.containsKey(userId)) {
mMap.put(userId, userId);
}
return mMap.get(userId);
}
思路是对的,但:getLock本身就会有并发问题;每个需要锁的接口都得new一个全局的HashMap;当10000个用户调用了100个接口总计要保存1000000条userId在内存里,服务器运行时间越长积累越多。
于是改成了如下方式,代码虽长了一点,但效率几乎没有下降:
/**
* 由于synchronized只能锁对象的地址,所有像Long为1000的用户id是锁不住的
* 此类来解决这个问题
* synchronized (UserLockUtils.getLock("test" + userId)) {}
* 因为是全局的入参当然是"接口名+userId"最好了
*/
public class UserLockUtils {
private static HashMapmMapId = new HashMap<>(), mMapIdCache = new HashMap<>();
/**
* 缓存切换的开始时间,等待{@link #mCacheDeleteTime}时间后将清空切换数据
*/
private static long mCacheCreatTime;
/**
* 最大缓存数(当超出这一数值时,会自动清空),缓存切换等待时间
*/
private static int mMaxCache = 1000, mCacheDeleteTime = 10000;
public static synchronized String getLock(String oldId) {
String returnSt;
if (mMapId.size() < mMaxCache) {//数据比较少,普通的返回锁
if (!mMapId.containsKey(oldId)) {
mMapId.put(oldId, oldId);
}
returnSt = mMapId.get(oldId);
} else {//累加的残留数据太多,切换至缓存
//缓存开始时间
long nowMills = System.currentTimeMillis();
if (mMapIdCache.size() == 0) {
mCacheCreatTime = nowMills;
}
if (!mMapIdCache.containsKey(oldId)) {
mMapIdCache.put(oldId, mMapId.getOrDefault(oldId, oldId));
}
returnSt = mMapIdCache.get(oldId);
//等待mCacheChangeTime时间后清除原始数据
if (nowMills - mCacheCreatTime > mCacheDeleteTime) {
mMapId.clear();
//原始和缓存对调即可实现切换
HashMapchange = mMapId;
mMapId = mMapIdCache;
mMapIdCache = change;
}
}
return returnSt;
}
}
举例:登录接口,我们只需要传“接口名+userId”就可以对登录接口的userId加锁了。
public void login(Long userId) {
synchronized (UserLockUtils.getLock("login" + userId)) {
// ...
}
}
尽量不要直接传userId哦,如果所有接口都直接传userId估计就锁死了。
java id 锁_java 多线程synchronized同步锁锁住相同用户Id相关推荐
- java 多线程 串行 加锁_java多线程 synchronized 与lock锁 实现线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样 的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 通过卖火车票的例子 火车站要卖票,我们 ...
- java中什么是释放已经持有的锁_java多线程什么时候释放锁
由于等待一个锁定线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不需要锁的时候及时释放锁是很重要的.在以下情况下,持有锁的线程会释放锁: 1.当前线程的同步方法.代码块执行结束的时候释放 ...
- java 线程的可重入锁_java 多线程-可重入锁
可重入锁:锁可以连续使用 计数器+判断进入的线程是不是已经锁定的线程,如果是那就不用等待,直接使用 public class my { public static void main(String[] ...
- java static 可见性_Java多线程 synchronized与可见性的关系以及可见性问题总结
作者:七里香的编程之路 出自:OSCHINA 原文:my.oschina.net/u/4098550/blog/4548274 能保证可见性的措施 除了volatile 可以让变量保证可见性外.hap ...
- java 同步锁_Java多线程:synchronized同步锁的使用和实现原理
作用和用法 在多线程对共享资源进行并发访问方面,JDK提供了synchronized关键字来进行线程同步,实现多线程并发访问的线程安全.synchronized的作用主要体现在三个方面:(1)确保线程 ...
- java中多线程模拟(多生产,多消费,Lock实现同步锁,替代synchronized同步代码块)...
import java.util.concurrent.locks.*; class DuckMsg{int size;//烤鸭的大小String id;//烤鸭的厂家和标号 DuckMsg(){}D ...
- java线程钥匙_Java多线程并发编程/锁的理解
一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...
- java线程池 锁_java多线程——锁
这是多线程系列第四篇,其他请关注以下: 如果你看过前面几篇关于线程的文字,会对线程的实现原理了然于胸,有了理论的支持会对实践有更好的指导,那么本篇会偏重于线程的实践,对线程的几种应用做个简要的介绍. ...
- java线程释放_Java多线程出现异常会自动释放锁
Java多线程出现异常会自动释放锁 package com.wkcto.intrinsiclock; /** * 同步过程中线程出现异常, 会自动释放锁对象 * * Author: 老崔 */ pub ...
- java线程 锁_Java多线程(二) 多线程的锁机制
当两条线程同时访问一个类的时候,可能会带来一些问题.并发线程重入可能会带来内存泄漏.程序不可控等等.不管是线程间的通讯还是线程共享数据都需要使用Java的锁机制控制并发代码产生的问题.本篇总结主要著名 ...
最新文章
- 通过小代码体验程序中BSS段和DATA段的差异
- cool venn diagram
- Python自动化运维——文件与目录差异对比
- 绘制方法太单一!?这三个宝藏在线学习资源推荐给你~~
- timerfd API使用总结
- 【算法系列之二】反波兰式
- kubectl apply -f_广州车展捷豹路虎参展阵容 全新F-PACE 路虎卫士90
- HDU 6188 Duizi and Shunzi
- 《ANSYS 14.0超级学习手册》一2.5 本章小结
- bzoj3172:[Tjoi2013]单词
- 资源—稀疏编码(sparse coding)
- Jq-模拟最大化最小化关闭
- CSS:border的属性
- conv、deconv、fractional-strided conv
- find:paths must precede expression问题及解决
- Adaptation---多屏幕多分辨率的支持和一些概念
- 炼数成金数据分析课程---13、回归分析
- 随机森林实例:利用基于CART算法的随机森林(Random Forest)树分类方法对于红酒质量进行预测
- stamen的程序员之路
- mysql永久事务隔离级别_MySQL的事务隔离级别