problem description
(1) there is a project that provides a unique ID
(2) according to the project name and table name, the project uses REDIS as the global lock (REDIS single-threaded feature, one batch at a time)
(3) the project provides an additional toolkit for the user to call to get the next ID
the following code is "the toolkit calls the consumer to get the next ID". Ask everyone to point out
(1) idProviderApi is a regular feign http method. Go to the ID service to get a batch of numbers
(2) getNextId will get the next ID
(3) it is divided into primary MAP and backup MAP, both of which are used to store a batch of numbers, the main one is used to provide ID directly, and the backup MAP is used to provide the main MAP when the master does not have a number. Then empty the backup MAP
(4) there is a timer to check whether the backup MAP has data. If not, go to the ID project to get
under your own test, if there are N threads in a node, it is the same to get ID temporarily. Please give us some advice
.related codes
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<String,IdProviderObj> map = new HashMap<String,IdProviderObj>();
//KEY
Map<String,IdProviderObj> backMap = new HashMap<String,IdProviderObj>();
//KEY
Map<String,ReentrantLock> lockMap = new HashMap<String,ReentrantLock>();
@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())) {
//,MAPMAP
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) + ",getIdbackMap");
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 isSetBackNullTRUEMAP;FALSEMAP
* @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() + ",");
}
});
}
}