java 点号_求神指,唯一ID项目,下面JAVA代码每个节点局部取号的方式有没有问题...

问题描述

(1)有一个提供唯一ID的项目

(2)项目根据项目名称和表名称,使用REDIS做为全局锁(REDIS单线程特性,每次取一批号)

(3)项目额外提供一个工具包,给使用者调用获取下一个ID

下面的代码就是“工具包给使用者调用获取下一个ID”,求各位大神指点下

(1)idProviderApi是常规feign http方法,去ID服务获取一批号

(2)getNextId就获取下一个ID

(3)分为主MAP和备份MAP,都是存储一批号,主的用于直接提供ID,备份MAP用于当主的没有号的时候提供给主MAP用,然后把备份MAP清空

(4)有定时器定时检测备份MAP是否有数据,如无,去ID项目获取

自己测试下,一个节点N个线程,暂时没出现获取ID是相同的,请各位大神指点下

相关代码

package com.jiangdaxian.project.biz;

import com.jiangdaxian.project.api.IdProviderApi;

import com.jiangdaxian.project.dto.IdProviderDto;

import com.jiangdaxian.project.request.IdProviderRequest;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.stereotype.Component;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.LongAdder;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

@Component

public class GetIdProviderInfo {

private static final String SPLIT = "_________";

//主存储数组

Map map = new HashMap();

//备用存储数组,当主存储第一次有数据时候,备用数组同时加KEY

Map backMap = new HashMap();

//每个KEY的锁

Map lockMap = new HashMap();

@Autowired

private IdProviderApi idProviderApi;

/**

* 获取下一个ID

* @param projectName,项目名称

* @param tableName,表名称

* @return

* @throws Exception

*/

public Long getNextId(String projectName,String tableName) throws Exception {

String key = getKey(projectName,tableName);

if(map.containsKey(key)==false){

//针对初始化

synchronized (key.intern()){

if(map.containsKey(key)==false) {

getNextIdProvider(projectName, tableName,true);

lockMap.put(getKey(projectName,tableName),new ReentrantLock());

getNextIdProvider(projectName, tableName,false);

}

}

}

IdProviderObj obj = map.get(key);

Lock lock = lockMap.get(key);

try {

//独占锁,10秒内拿不到直接出错

boolean result = lock.tryLock(10, TimeUnit.SECONDS);

if (result == false) {

throw new Exception("取号超时");

}

return getId(obj,projectName, tableName);

}catch(Exception e){

e.printStackTrace();

throw e;

}finally {

lock.unlock();

}

}

private Long getId(IdProviderObj obj,String projectName,String tableName) throws Exception {

long nextId = obj.getNowId().longValue();

obj.getNowId().increment();

if (nextId > (obj.getIdProviderDto().getIdEnd())) {

//重新取号,如果备份MAP有,用备份MAP的顶上,否则直接获取

IdProviderObj getObj= backMap.get(getKey(projectName,tableName));

if(getObj!=null && getObj.getIdProviderDto()!=null){

//如果备份有,移动到主的MAP上,备份的清空

map.put(getKey(projectName,tableName),getObj);

backMap.put(getKey(projectName,tableName),null);

System.out.println("obj " + getKey(projectName,tableName) + ",getId时候,从backMap获取");

return getId(getObj,projectName, tableName);

}else{

//如果访问太大,导致备份的来不及定时补充信息的话,直接去ID服务拿

IdProviderObj idProviderObj = getNextIdProvider(projectName, tableName,true);

System.out.println("obj " + getKey(projectName,tableName) + ",getId时候,从远程获取");

return getId(idProviderObj,projectName,tableName);

}

} else {

//正常取号

return nextId;

}

}

/**

*

* @param projectName

* @param tableName

* @param isSetBackNull,保存在哪里,TRUE,保存在主MAP;FALSE,保存在备份MAP

* @return

* @throws Exception

*/

private IdProviderObj getNextIdProvider(String projectName, String tableName,boolean isSetBackNull) throws Exception {

IdProviderObj idProviderObj = new IdProviderObj();

try {

IdProviderRequest idProviderRequest = new IdProviderRequest();

idProviderRequest.setTableName(tableName);

idProviderRequest.setProjectName(projectName);

IdProviderDto dto = idProviderApi.get(idProviderRequest);

if(dto!=null && dto.getId()!=null) {

idProviderObj.setIdProviderDto(dto);

LongAdder la = new LongAdder();

la.add(dto.getIdStart());

idProviderObj.setNowId(la);

if(isSetBackNull==true) {

map.put(getKey(projectName,tableName), idProviderObj);

backMap.put(getKey(projectName, tableName), null);

}else{

backMap.put(getKey(projectName, tableName), idProviderObj);

}

return idProviderObj;

}else{

throw new Exception();

}

}catch(Exception e){

e.printStackTrace();

throw e;

}

}

private class IdProviderObj{

private IdProviderDto idProviderDto = null;

private LongAdder nowId;

public IdProviderDto getIdProviderDto() {

return idProviderDto;

}

public void setIdProviderDto(IdProviderDto idProviderDto) {

this.idProviderDto = idProviderDto;

}

public LongAdder getNowId() {

return nowId;

}

public void setNowId(LongAdder nowId) {

this.nowId = nowId;

}

}

private class NameObj{

private String projectName;

private String tableName;

public String getProjectName() {

return projectName;

}

public void setProjectName(String projectName) {

this.projectName = projectName;

}

public String getTableName() {

return tableName;

}

public void setTableName(String tableName) {

this.tableName = tableName;

}

}

private String getKey(String projectName,String tableName){

return projectName + SPLIT+tableName;

}

private NameObj getNameObj(String str){

NameObj nameObj = new NameObj();

String []arr = str.split(SPLIT);

nameObj.setProjectName(arr[0]);

nameObj.setTableName(arr[1]);

return nameObj;

}

@Scheduled(cron = "0/10 * * * * *")

public void addIdProviderDto(){

backMap.entrySet().parallelStream().forEach(obj->{

if(obj.getValue()==null){

System.out.println("obj " + obj.getKey() + ",没有数据,正在定时补充数据");

NameObj nameObj = getNameObj(obj.getKey());

try {

getNextIdProvider(nameObj.getProjectName(),nameObj.getTableName(),false);

} catch (Exception e) {

e.printStackTrace();

}

}else{

System.out.println("obj " + obj.getKey() + ",有数据,无需处理");

}

});

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值