超时唤醒等待线程
之前工作中,涉及的项目是软硬接口请求。具体的请求链路:前端发送请求到后端,后端进行报文拼接,将请求发送到硬件机器,硬件机器通过响应报文,回复请求,后端处理报文后,返回结果给前端。
图示如下

注:图中的线程均指JAVA运行程序的线程!
有几个值得讨论的地方,前端请求线程请求走到后端,后端线程需要携带数据给前端(正常数据/执行出错)。讨论点1.这个请求线程是否需要暂时休眠?讨论点2.是否需要设置超时返回,避免前端等待时间过长?
请求线程是否需要暂时休眠
个人倾向于休眠,因为等待的这个时间,CPU还是会给这个线程进行时间片的分配,造成CPU的利用率低,浪费计算的资源。
避免前端等待时间过长,需要设置超时返回
是的,这个事情很有必要,因为我们对外呈现给用户的界面显示不宜时间过长,让用户误认为系统问题。
既然确定了方向,那我们就想办法去解决这个问题。
整体设计

注:线程B这个动作 也可以由线程A直接请求,看具体的设置。
线程A,D,C必须要有一个共享标志,通过某种机制能找到具体的锁对象,这样才能进行线程之间的通信。
假如在特定的时间内,线程C先收到了结果,那么线程C就先进行唤醒操作,将线程A进行唤醒。若线程C迟迟未收到结果,超过了等待时间,那么就将会由线程D进行唤醒操作。
本人简单落地实现了代码
package com.tang.web_standard.timeout; import lombok.Data; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; @Data public class TimeoutLock { /** * 锁对象 */ private ReentrantLock reentrantLock = new ReentrantLock(); private Condition condition = reentrantLock.newCondition(); /** * 处理结果 */ private boolean flag; /** * 结果 */ private Object result; }
package com.tang.web_standard.timeout; import java.util.HashMap; import java.util.Map; public class TimeoutUtil { /** * key 可以根据数据 */ public static final Map<Integer, TimeoutLock> lockMap = new HashMap<>(); }
package com.tang.web_standard.timeout; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Objects; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @RestController public class TimeoutController { public static final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3); @RequestMapping("/timeout") public String timeout() { /** * 前置处理 */ // 准备创建超时唤醒 TimeoutLock timeoutLock = new TimeoutLock(); Integer key = Integer.valueOf(1); TimeoutUtil.lockMap.put(key, timeoutLock); createTimeoutTask(key, 5); timeoutLock.getReentrantLock().lock(); try { System.out.println("准备休眠"); timeoutLock.getCondition().await(); System.out.println("被唤醒!"); } catch (Exception e) { e.printStackTrace(); } finally { timeoutLock.getReentrantLock().unlock(); } if (timeoutLock.isFlag()) { return timeoutLock.getResult().toString(); } return "超时唤醒"; } /** * @param key map中的key值 * @param timeout 单位S */ private void createTimeoutTask(Integer key, int timeout) { scheduledThreadPoolExecutor.schedule(() -> { TimeoutLock timeoutLock = TimeoutUtil.lockMap.get(key); if (Objects.nonNull(timeoutLock)) { timeoutLock.getReentrantLock().lock(); try { System.out.println("=====超时唤醒!!!!"); timeoutLock.getCondition().signalAll(); System.out.println("通知成功!!!!"); } catch (Exception e) { e.printStackTrace(); } finally { timeoutLock.getReentrantLock().unlock(); } } }, 5, TimeUnit.SECONDS); } }
浙公网安备 33010602011771号