需求:CS 架构的客户端批量打印功能要做到控制单个客户端操作,不可多客户端同时操作批量打印,因为批量打印调的后台接口流水码生成是续流的,任何一个Client调用都续流,多客户端同时调用批量打印,一次批量打印出的流水码就可能跳码。接口服务是分布式的,如果单服务接口,可以用同步锁来实现。
思路:利用 redis 缓存标识是否有 Client 正在使用批量打印功能,操作批量打印功能时都查询(查询服务接口分布式的)一次这个缓存标识,没 Client 操作中就可操作批量打印功能,同时标识有客户端正在操作中,不让别的客户端操作,批量打印操作完成之后释放操作权限(批量打印异常也要释放),标识没有客户端正在操作。
每个Client 操作批量打印功能前查询这个标识时利用分布式锁技术,可参考博文1 和 博文2,谁先操作谁先抢到查询标识的权限,按查询标识结果提示是否等待一段时间再操作批量打印。
这个思路设计待测试,理论上应该是行得通的。
猿友们若有好的思路建议,欢迎留言。
测试结果出来了:
2020-04-04 14:13:58 Thread[客户端窗口10,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:58 Thread[客户端窗口18,5,main] 批量打印中 2020-04-04 14:13:58 Thread[客户端窗口2,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:58 Thread[客户端窗口13,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:58 Thread[客户端窗口11,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:58 Thread[客户端窗口5,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:58 Thread[客户端窗口3,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:58 Thread[客户端窗口15,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:58 Thread[客户端窗口18,5,main] 批量打印完成 2020-04-04 14:13:59 Thread[客户端窗口17,5,main] 批量打印中 2020-04-04 14:13:59 Thread[客户端窗口19,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:59 Thread[客户端窗口14,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:59 Thread[客户端窗口7,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:59 Thread[客户端窗口9,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:59 Thread[客户端窗口12,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:59 Thread[客户端窗口16,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:13:59 Thread[客户端窗口17,5,main] 批量打印完成 2020-04-04 14:14:00 Thread[客户端窗口6,5,main] 批量打印中 2020-04-04 14:14:00 Thread[客户端窗口20,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:14:00 Thread[客户端窗口6,5,main] 批量打印完成 2020-04-04 14:14:01 Thread[客户端窗口8,5,main] 批量打印中 2020-04-04 14:14:01 Thread[客户端窗口4,5,main]有客户端正在批量打印中,请稍后再试! 2020-04-04 14:14:01 Thread[客户端窗口8,5,main] 批量打印完成 2020-04-04 14:14:02 Thread[客户端窗口1,5,main] 批量打印中 2020-04-04 14:14:02 Thread[客户端窗口1,5,main] 批量打印完成
import jodd.datetime.JDateTime; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; public class MyThreed implements Runnable { private final String URL = "http://……/get-batchlabelflag"; @Override public void run() { try { HttpClient httpClient = HttpClientBuilder.create().build(); HttpGet httpGet = new HttpGet(URL); HttpResponse resultRep = httpClient.execute(httpGet); String msg = EntityUtils.toString(resultRep.getEntity()); if ("true".equals(msg)) { JDateTime jdt = new JDateTime(); System.out.println(jdt.toString("YYYY-MM-DD hh:mm:ss")+" "+Thread.currentThread().toString().replaceFirst(",5,main","") +" 有客户端正在批量打印中,请稍后再试!"); } else { // 有权限执行批量打印功能 // 模拟批量打印时间 JDateTime jdt = new JDateTime(); System.out.println(jdt.toString("YYYY-MM-DD hh:mm:ss") +" "+Thread.currentThread().toString().replaceFirst(",5,main","") + " 批量打印中"); Thread.sleep(3000); HttpPut put = new HttpPut(URL); httpClient.execute(put); jdt = new JDateTime(); System.out.println(jdt.toString("YYYY-MM-DD hh:mm:ss") +" "+Thread.currentThread().toString().replaceFirst(",5,main","") + " 批量打印完成"); } } catch (Exception e) { } } }
public class ThreedTest { public static void main(String[] args) { //得到对象 MyThreed mtd = new MyThreed(); //把对象放入线程中 Thread t1 = new Thread(mtd, "客户端01"); Thread t2 = new Thread(mtd, "客户端02"); Thread t3 = new Thread(mtd, "客户端03"); Thread t4 = new Thread(mtd, "客户端04"); Thread t5 = new Thread(mtd, "客户端05"); Thread t6 = new Thread(mtd, "客户端06"); Thread t7 = new Thread(mtd, "客户端07"); Thread t8 = new Thread(mtd, "客户端08"); Thread t9 = new Thread(mtd, "客户端09"); Thread t10 = new Thread(mtd, "客户端10"); Thread t11 = new Thread(mtd, "客户端11"); Thread t12 = new Thread(mtd, "客户端12"); Thread t13 = new Thread(mtd, "客户端13"); Thread t14 = new Thread(mtd, "客户端14"); Thread t15 = new Thread(mtd, "客户端15"); Thread t16 = new Thread(mtd, "客户端16"); Thread t17 = new Thread(mtd, "客户端17"); Thread t18 = new Thread(mtd, "客户端18"); Thread t19 = new Thread(mtd, "客户端19"); Thread t20 = new Thread(mtd, "客户端20"); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); t7.start(); t8.start(); t9.start(); t10.start(); t11.start(); t12.start(); t13.start(); t14.start(); t15.start(); t16.start(); t17.start(); t18.start(); t19.start(); t20.start(); } }