栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

什么是id锁(id锁有什么影响)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

什么是id锁(id锁有什么影响)

对用户ID相同进行加锁的四种方法

先上代码

package com.nft.service.lock;

import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;


public class LockUtils {
	// 对其相同的玩家ID进行加锁
	private static Map locks = new ConcurrentHashMap<>();
	// 用户登录的时候,防止同一邮箱注册出现错误
	private static Map locks_login = new ConcurrentHashMap<>();
	// 当玩家进入系统的时候,需要锁住机器人的ID,防止相同的玩家获取到同一个机器人信息
	private static Map locks_replace_reboot = new HashMap<>();
	// 卡牌的体力
	private static Map locks_power = new ConcurrentHashMap<>();
	// 同步srar系统中的玩家信息
	private static Map LOCKS_SYN_STAR = new ConcurrentHashMap<>();
	//给玩家发放奖励的时候,防止玩家写入同一个类型的奖励ID
	private static Map LOCKS_GRANT_REWARD = new ConcurrentHashMap<>();
	//用于防止玩家的积分丢失
	private static Map> LOCKS_USER_INTEGRAL = new ConcurrentHashMap<>();
	
	public static void getLockByUserIntegral(final long userId) {
		ReentrantLock lock=null;
		SoftReference softReference=LOCKS_USER_INTEGRAL.get(userId);
		if(softReference==null) {
			synchronized (LOCKS_USER_INTEGRAL) {
				softReference=LOCKS_USER_INTEGRAL.get(userId);
				if(softReference==null) {
					lock=new ReentrantLock();
					softReference = new SoftReference(lock);
					LOCKS_USER_INTEGRAL.put(userId, softReference);
				}
			}
		}
		softReference.get().lock();
	}

	public static void unLockByUserIntegral(final long userId) {
		SoftReference lock=LOCKS_USER_INTEGRAL.get(userId);
		lock.get().unlock();
	}
	
	public static Object getLockByGrantReward(final long userId) {
		LOCKS_GRANT_REWARD.putIfAbsent(userId, userId);
		return LOCKS_GRANT_REWARD.get(userId);
	}

	public static void unLockByGrantReward(final long userId) {
		LOCKS_GRANT_REWARD.remove(userId);
	}
	
	public static Object getLockBySynStar(final String synUserId) {
		LOCKS_SYN_STAR.putIfAbsent(synUserId, synUserId);
		return LOCKS_SYN_STAR.get(synUserId);
	}

	public static void unLockBySynSstar(final String synUserId) {
		LOCKS_SYN_STAR.remove(synUserId);
	}

	public static synchronized boolean getLockByReplaceReboot(final Integer rebootId) {
		if (locks_replace_reboot.get(rebootId) == null) {
			locks_replace_reboot.put(rebootId, rebootId);
			return true;
		}
		return false;
	}

	public static void unLockByReplaceReboot(final Integer rebootId) {
		locks_replace_reboot.remove(rebootId);
	}

	public static Object getLockByLogin(final String email) {
		locks_login.putIfAbsent(email, email);
		return locks_login.get(email);
	}

	public static void unLockByLogin(final String email) {
		locks_login.remove(email);
	}

	public static Object getLockByPower(final long id) {
		locks_power.putIfAbsent(id, id);
		return locks_power.get(id);
	}

	public static void unLockByPower(final long id) {
		locks_power.remove(id);
	}

	// 对其相同的玩家ID进行加锁
	public static Object getCacheSyncObject(final long id) {
		locks.putIfAbsent(id, id);
		return locks.get(id);
	}

	public static void unLock(final long id) {
		locks.remove(id);
	}
}

用于解决我们在项目中对同一个用户的资源进行加锁的时候

比如:在项目开发过程中,由多中情况在对同一个邮箱进行注册的时候,我们只对单个邮箱进行加锁,而不对所有的邮箱字符串加锁,再或者用户在支付的时候,不能多个浏览器进行同时支付吧,这个时候,就需要进行锁操作了,对单独的一个用户进行上锁,进行一次性的支付,预防用户的资产不足,而对其他用户不受操作影响

第一种方案:
	private static Map LOCKS_GRANT_REWARD = new ConcurrentHashMap<>();
	public static Object getLockByGrantReward(final long userId) {
		LOCKS_GRANT_REWARD.putIfAbsent(userId, userId);
		return LOCKS_GRANT_REWARD.get(userId);
	}

	public static void unLockByGrantReward(final long userId) {
		LOCKS_GRANT_REWARD.remove(userId);
	}

如何使用呢?

	synchronized(LockUtils.getLockByGrantReward(userId)) {
			try {
				grantReward(rewardGoodsPO, userId);
			}finally {
				LockUtils.unLockByGrantReward(userId);
			}
		}

ConcurrentHashMap java8对其进行了优化,分段锁机制,当然了,使用HashMap也是可以的,但这边对其移除的时候,没有做更多的代码操作
使用 ConcurrentHashMap 的 putIfAbsent 进行操作放入数据,因为 如果传入key对应的value已经存在,就返回存在的value,不进行替换。如果不存在,就添加key和value,返回null
所以 putIfAbsent 使用的还是之前的数据,从而达到synchronized 锁住相同的数据

第二种方案

使用的是String的常量池,但这里有个问题是,如果用户ID非常庞大,则不是很适合

	synchronized("XX".intern()) {//防止重复的文件放到相同目录下
		// TODO
	});

String 的 intern 返回的是常量池的数据,所以使用Synchronized 的时候,使用的还是相同的数据

第三种方案

使用的是HashMap的方式

	private static Map locks_replace_reboot = new HashMap<>();
	public static synchronized boolean getLockByReplaceReboot(final Integer rebootId) {
		if (locks_replace_reboot.get(rebootId) == null) {
			locks_replace_reboot.put(rebootId, rebootId);
			return true;
		}
		return false;
	}

	public static void unLockByReplaceReboot(final Integer rebootId) {
		locks_replace_reboot.remove(rebootId);
	}

使用方法

try {
	if(LockUtils.getLockByReplaceReboot(homeRebootId)){
		// TODO
	}
}finally {
	LockUtils.unLockByReplaceReboot(homeRebootId);			
}
第四种方案
// SoftReference 软引用 ,在内存不足的情况下,进行垃圾回收
private static Map> LOCKS_USER_INTEGRAL = new ConcurrentHashMap<>();
	public static void getLockByUserIntegral(final long userId) {
		ReentrantLock lock=null;
		SoftReference softReference=LOCKS_USER_INTEGRAL.get(userId);
		if(softReference==null) {
			synchronized (LOCKS_USER_INTEGRAL) {
				softReference=LOCKS_USER_INTEGRAL.get(userId);
				if(softReference==null) {
					lock=new ReentrantLock();
					softReference = new SoftReference(lock);
					LOCKS_USER_INTEGRAL.put(userId, softReference);
				}
			}
		}
		softReference.get().lock();
	}

	public static void unLockByUserIntegral(final long userId) {
		SoftReference lock=LOCKS_USER_INTEGRAL.get(userId);
		lock.get().unlock();
	}

使用方法

	try {
			LockUtils.getLockByUserIntegral(userId);
			updateOrInsertUserIntergral(userId, intergral, plan);
		}finally {
			LockUtils.unLockByUserIntegral(userId);
		}

当然了,如有不足之处,请指出

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/773334.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号