一套手写的计时任务工具

记得之前有一家公司的面试问随机数排序算法,有一个大佬玩的花招,他用多线程的睡眠机制,去开辟多线程同时睡眠,随机数小的就会先唤醒打印,这样就实现了排序,如果降序也很简单,只需要将先唤醒的存到数组的最后面,将指针前移。

那么我就诞生一个想法,这种机制可以用到计时任务中去,当然前提是任务很少,或者说就只适合学生做项目用,不适合生产,玩着来呗。

来一起看看:

任务信息实体:

@Data
public class TaskInfo {
    private String TaskServerName;
    private Integer TaskTime;
    private TaskType Type = TaskType.TASK_DELETE_CACHE;

    public TaskInfo(String serverName, Integer taskTime, TaskType type){
        this.TaskServerName = serverName;
        this.TaskTime = taskTime;
        this.Type = type;
    }
    public TaskInfo(){

    }
}

任务结束后是否留缓存或者数据库枚举

public enum TaskType {
    /*计时结束即删除、计时结束不删除仅仅修改时间、计时结束不删除进入数据库*/
    TASK_DELETE_CACHE,TASK_INTER_CACHE,TASK_SUPER_CACHE
}

计时任务存储的数据结构

public class TimerHashMap implements Map<String,TaskInfo>{
    /*单例模式下堆内存只有一个静态的baseData极其容易在多线程环境下出现异常,上一把对象锁*/
    private final static HashMap<String, TaskInfo> baseData = new HashMap<>(20);

    public boolean endTaskInCache(String key,TaskInfo taskInfo){
        synchronized (baseData){
            if (baseData.containsKey(key)){
                boolean remove = baseData.remove(key,taskInfo);
                if (remove){
                    taskInfo.setTaskTime(0);
                    TaskInfo put = baseData.put(key, taskInfo);
                    return put == null;
                }
                return false;
            }
            return false;
        }
    }

    @Override
    public int size() {
        return baseData.size();
    }

    @Override
    public boolean isEmpty() {
        return baseData.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return baseData.containsKey(key);
    }

    @Override
    public boolean containsValue(Object value) {
        return baseData.containsValue(value);
    }

    @Override
    public TaskInfo get(Object key) {
        synchronized (baseData) {
            return baseData.get(key);
        }
    }

    @Nullable
    @Override
    public TaskInfo put(String key, TaskInfo value) {
       synchronized (baseData){
           return baseData.put(key,value);
       }
    }

    @Override
    public TaskInfo remove(Object key) {
        synchronized (baseData){
            return baseData.remove(key);
        }
    }

    @Override
    public void putAll(@NotNull Map<? extends String, ? extends TaskInfo> m) {
       synchronized (baseData){
            baseData.putAll(m);
       }
    }

    @Override
    public void clear() {
        synchronized (baseData){
            baseData.clear();
        }
    }

    @NotNull
    @Override
    public Set<String> keySet() {
        synchronized (baseData){
            return baseData.keySet();
        }
    }

    @NotNull
    @Override
    public Collection<TaskInfo> values() {
        synchronized (baseData){
            return baseData.values();
        }
    }

    @NotNull
    @Override
    public Set<Entry<String, TaskInfo>> entrySet() {
        synchronized (baseData){
            return baseData.entrySet();
        }
    }
}

计时任务注册与运行组件

/**
 * 计时任务(依赖与hashmap数据结构,结合线程池中特定线程的睡眠实现计时功能)
 */
@Component
public class TimerTask {
    @Resource
    private TimerHashMap timer;
    @Resource
    private ThreadPoolTaskExecutor userThreadPoolTaskExecutor;

    /**
     * 计时任务的注册与任务完毕后的销毁以及存留
     * @param serverKey 计时任务标识字段
     * @param taskInfo 计时任务信息
     */
    public void setTimer(String serverKey, TaskInfo taskInfo) {
        boolean sign = timer.containsKey(serverKey);
        if (sign)
            return;
        try {
            userThreadPoolTaskExecutor.execute(
                    new Thread(
                            () -> {
                                TaskInfo put = timer.put(serverKey, taskInfo);
                                if (put == null) {
                                    try {
                                        System.out.println(Thread.currentThread().getName()+serverKey+"计时开始------>");
                                        Thread.sleep(taskInfo.getTaskTime());
                                        if (taskInfo.getType() == TaskType.TASK_DELETE_CACHE) {
                                            TaskInfo remove = timer.remove(serverKey);
                                            if (remove == null)
                                                throw new Exception("计时任务删除失败");
                                        }else if (taskInfo.getType()== TaskType.TASK_INTER_CACHE){
                                            boolean result = timer.endTaskInCache(serverKey, taskInfo);
                                            if (!result){
                                                throw new Exception("计时任务无法正常结束");
                                            }
                                        }else {
                                            /*将计时任务插入计时任务数据库.....*/
                                        }
                                        System.out.println(Thread.currentThread().getName()+serverKey+"任务结束------>");
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            },
                            serverKey
                    )
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断计时任务是否结束
     * @param serverKey 计时任务标识字段
     * @return 是否已经结束
     */
    public boolean taskIsEnd(String serverKey){
        boolean result = timer.containsKey(serverKey);
        if (result){
            return timer.get(serverKey).getTaskTime() == 0;
        }
        return false;
    }
}

线程池与计时任务存储数据结构配置在Application中:

@Bean(name = "userThreadPoolTaskExecutor")
    public ThreadPoolTaskExecutor getUserThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //此方法返回可用处理器的虚拟机的最大数量; 不小于1
        //int core = Runtime.getRuntime().availableProcessors();
        int core = 1;
        //设置核心线程数
        executor.setCorePoolSize(core);
        //设置最大线程数
        executor.setMaxPoolSize(core * 2 + 1);
        //除核心线程外的线程存活时间
        executor.setKeepAliveSeconds(3);
        //如果传入值大于0,底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue
        executor.setQueueCapacity(40);
        //线程名称前缀
        executor.setThreadNamePrefix("userService-thread-execute");
        //设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /*保证多线程之间共享某些参数从而定义链表图数据结构实现某些数据的共享:可使用java关键字替代*/
    @Bean(name = "cache")
    public Map<String, String> StringCache() {
        return new LinkedHashMap<>();
    }

    /*注入自定义计时任务采用的数据结构,类似于redis里的数据结构*/
    @Bean(name = "timer")
    public TimerHashMap TimerCache(){
        return new TimerHashMap();
    }

这套工具能够实现redis的缓存过期功能,但是不支持过多的线程开销,玩玩可以,别当真。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ForestSpringH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值