超时唤醒等待线程

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

  图示如下

  注:图中的线程均指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);
    }

}

 

posted @ 2023-11-02 14:00  琼尼-沃克  阅读(36)  评论(0)    收藏  举报