打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
java项目实现流水号自动增长(分布式环境)

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

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

@Servicepublic 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<timeUnit.toNanos(timeOut));        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();        }    }}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
layUi
SpringBoot统一返回结果
WPF的一种动态切语言方法
Spring Boot统一异常处理
java并发编程学习15
枚举注解形式,优化if else代码
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服