java项目跨年流水号_java项目实现流水号自动增长-2-分布式环境

1、上一篇说的流水号自动增长,存在两个问题,第一如果编号是字母+数字格式的,数字自增可以使用AtomicInteger实现,但是与字母组合拼接肯定是一个非原子、非线程安全的,可以通过线程同步实现;第二是如果服务集群部署,涉及到分布式锁问题。

下面的这个例子就是解决分布式环境下实现流水号自动增长的功能,通过线程同步+redis分布式锁实现。

代码实例如下:

@Service

public class DistributedLock {

@Autowired

private IRedisDao redisDao;

@Autowired

private IUserDao userDao;

//用户编码当前最大值,存储在redis中的key

private static final String CURRENT_MAX_USER_CODE_KEY = "CURRENT_MAX_USER_CODE_KEY";

//用户编码前缀

private final static String PRE_GROUP_CODE = "w";

//用户编码初始值,格式:前缀+8000000开始的流水,如:w8000001

private static final String INIT_USER_CODE = PRE_GROUP_CODE+"8000000";

//分布式锁的锁定时长,单位秒

private static final int LOCK_TIME = 5;

//分布式锁的key

private static final String LOCK_KEY = "USER_CODE_INC_LOCK";

//缓存初始化

@PostConstruct

public void initCurrentMaxUserCode(){

//初始化获取数据库中最大编码值

String currentMaxUserCode = userDao.getMaxUserCode();

//如果为空,则设置为初始值

if(StringUtils.isBlank(currentMaxUserCode)){

currentMaxUserCode = INIT_USER_CODE;

}

redisDao.set(CURRENT_MAX_USER_CODE_KEY, currentMaxUserCode,0);

}

/**

* @Author javaloveiphone

* @Date 创建时间:2017年4月8日

* @Description :获取最大编码值,当前服务被部署多套,采用:synchronized+redis分布式锁 形式共同完成

* @param timeOut 循环获取最大值超时时长

* @param timeUnit 超时单位

* @return

* String

*/

public synchronized String getNewMax(long timeOut,TimeUnit timeUnit){

String newMaxValue = null;

if(timeUnit == null){

timeUnit = TimeUnit.SECONDS;

}

long start = System.nanoTime();

do{

String lockValue = String.valueOf(new Date().getTime());

int lockFlag = redisDao.setnx(LOCK_KEY, lockValue).intValue();

//获取锁

if(lockFlag == 1){

//1、设置有效期,防止当前锁异常或崩溃导致锁释放失败

redisDao.expire(LOCK_KEY, LOCK_TIME);

//2、获取当前最大编码值

String currentMaxValue = (String)redisDao.get(CURRENT_MAX_USER_CODE_KEY);

//如果redis中该值丢失,重新执行初始化

if(StringUtils.isBlank(currentMaxValue)){

initCurrentMaxUserCode();

currentMaxValue = (String)redisDao.get(CURRENT_MAX_USER_CODE_KEY);

}

//3、将最大值加1,获取新的最大值

int currentMaxNum = Integer.parseInt(currentMaxValue.substring(currentMaxValue.indexOf(PRE_GROUP_CODE)+1));

newMaxValue = PRE_GROUP_CODE + (currentMaxNum + 1);

//4、将新的最大值同步到redis缓存

redisDao.set(CURRENT_MAX_USER_CODE_KEY, newMaxValue,0);

//5、释放锁,redis执行删除方法

redisDao.remove(LOCK_KEY);

break;

//未获取锁

}else if(lockFlag == 0){

System.out.println(Thread.currentThread().getName()+"=====未获取锁,未超时将进入循环");

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

//如果未超时,则循环获取锁

}while(System.nanoTime()-start

return newMaxValue;

}

public void getMaxUserCode(){

for(int i=0;i<10;i++){

Thread t = new Thread(){

@Override

public void run() {

System.out.println(getNewMax(5,TimeUnit.SECONDS));

}

};

t.setName("线程"+i);

t.start();

}

}

}

参考:http://blog.csdn.net/x_i_y_u_e/article/details/50864205

http://blog.csdn.net/java2000_wl/article/details/8740911

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值