本文记录在开发过程,JAVA如何利用ReentrantLock实现多线程并发生成唯一的流水号。
在实际的开发中,我们会经常碰到需要生成唯一流水号的业务场景。有些情况可以采用数据库自定义序列号自增生成流水号,亦或是自己编写数据库触发器生成流水号。但本文以代码实操为主,记录在代码层面上如何利用ReentrantLock,实现多线程同时请求时也能确保流水号取得唯一的场景。
ReentrantLock锁原理在本文中不再阐述,详细的讲解可参考此文:https://blog.csdn.net/zhengzhaoyang122/article/details/110847701
一、编写流水号的生成类
ReentrantLock锁的运用其实很简单,在方法中如下添加即可,简单的调用业务前先上锁,调用完后释放锁。这里我采用简单的年月日+流水的规则生成流水号。
public class GetSerialNum {/**记录已有流水单*/public static int num = 0;private static ReentrantLock lock = new ReentrantLock();public static String getNum() {String unique = "";//上锁lock.lock();try {//------------------流水号业务逻辑----------------//5位流水号if (num == 0) {//当天第一份流水单号unique = new SimpleDateFormat("yyyyMMdd").format(new Date()) + "01";} else {//当天最后的订单流水号累加1String nums = String.valueOf(num + 1);//设定具体流水为两位数,单数则补齐前面的0StringBuilder sb = new StringBuilder(nums);for (int i = nums.length(); i < 2; i++) {sb.insert(0, "0");}unique = new SimpleDateFormat("yyyyMMdd").format(new Date()) + sb.toString();}//已有流水单+1num++;//----------------------------------} catch (Exception e) {e.printStackTrace();} finally {//释放锁lock.unlock();}return "TEST" + unique;}
}
二、编写测试样例验证
这里我们利用CyclicBarrier类来模仿进行大量并发的测试。CyclicBarrier是JDK1.5的java.util.concurrent并发包中提供的一个并发工具类。
1.准备一个Task线程类。
public class Task implements Runnable {private static final Logger logger = Logger.getLogger("log");private CyclicBarrier cyclicBarrier;public Task(CyclicBarrier cyclicBarrier) {this.cyclicBarrier = cyclicBarrier;}@Overridepublic void run() {try {// 等待所有任务准备就绪cyclicBarrier.await();// 测试内容logger.info(GetSerialNum.getNum());} catch (Exception e) {e.printStackTrace();}}}
2.程序测试主入口,设定同时并发50个线程。
public class TestLock {public static void main(String[] args) {int count = 50;CyclicBarrier cyclicBarrier = new CyclicBarrier(count);ExecutorService executorService = Executors.newFixedThreadPool(count);for (int i = 0; i < count; i++) {executorService.execute(new Task(cyclicBarrier));}executorService.shutdown();while (!executorService.isTerminated()) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}
三、后台输出测试结果
可以看到同一秒里,我们每条线程获取到的流水号都是唯一不重复的。


















