自己实现定制自己的专属java锁,来高效规避不稳定的第三方

  java juc 包下面已经提供了很多发锁工具供我们使用,但在日常开发中,为了各种原因我们总是会用多线程来发处理一些问题,然而并不是所有的场景都可以使用juc 或者java本身提供的锁来方便的帮助我们控制多线程带来的并发问题,这个时候就需要我们根据自己的业务场景来子实现定制一把我们自己专属的锁,来满足我们的需要。

  假设系统对接了很多第三方公司,来帮助我们完成业务,但这些第三方的服务接口稳定性参差不齐,以往的过程中我们可能会做一些监控措施来帮助我们监控接口的稳定性,但这会存在一个问题,就是当我们监控到操作失败的时候其实已经会有用户产生操作失败的结果了,这对重视用户体验的互联网公司肯定是不能忍的,为此我们可以每个用户来访问时都同时调用多个第三方,只要有一个返回结果,我们就可以给用户做相应的展示,这样即使有一两个第三方出现故障对用户也是无感知的,但另一个问题来了,同时并发调用第三方我怎么全选哪个结果呢,很简单,当然是返回最快的了!具体如何选用最快的返回结果就用到我们今天的主题了,定制自己的锁。

  上面所说的大致流程可以描述为这样:接受用户请求  →  多线程组装报文调用第三方 → 阻塞等待 → 任意结果返回唤醒主线程继续处理。基于此流程很自然想到这个阻塞其实就可以用多线程中的锁来实现,主线程在将任务提交给线程池多线程处理后,去获取一个锁,而这个锁需要在线程中第一个第三方返回结果时才能获取到,这样就让主线程继续执行,有了大概思路,我们来看下具体如何实现。

  看过java 源码的同学对AbstractQueuedSynchronizer一定不会陌生,java中的很多锁ReentrantLock 、ReadWriteLock  、ReentrantReadWriteLock 和一些其他的并发工具CountDownLatch、 Semaphore等都基于此抽象类实现,AbstractQueuedSynchronizer中通过一个FIFO队列来管理等待加锁的线程,通过一个state的int变量控制线程加锁状态,其内部也帮我实现了线程获得锁和挂起的方法,我们这里参考CountDownLatch来实现,因为我们的需求和CountDownLatch正好相反,CountDownLatch是多个线程都处理完才能继续,而我们是只要有一个处理完就能继续,简单来说就是主线程唤醒的判断条件不一致。先来看下CountDownLatch的使用:

  

public static void main(String[] args) throws InterruptedException { CountDownLatch await = new CountDownLatch(5); // 依次创建并启动线程 for (int i = 0; i < 5; ++i) { new Thread(new MyRunnable(await)).start(); } await.await(); System.out.println("over!"); } class MyRunnable implements Runnable { private final CountDownLatch await; public MyRunnable(CountDownLatch await) { this.await = await; } public void run() { try { //业务处理 await.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsdxf.html