【问题标题】:Insert object to a map with ttl使用 ttl 将对象插入地图
【发布时间】:2021-11-26 11:41:51
【问题描述】:

我正在尝试实现某种具有以下特征的地图。

应在生存时间过去后删除每个项目(除非生存时间为 0,然后该项目不会过期) get、put、remove、size 的平均复杂度都应该是 o(1)

我在构造函数中调用了一个线程,该线程进入 while(true) 循环并检查 ttl 是否已过期

线程的代码

    class ttlWatchdog extends Thread {
    @SneakyThrows
    @Override
    public void run() {
        long timeToSleep ;
        System.out.println("Initiating Cleaner Thread..");
        while (true) {
            timeToSleep = checkExpiredKeys();//need to change it to a diffrent
            //System.out.println("thread will sleep for  " + timeToSleep + "msc" );
            Thread.sleep(timeToSleep);

        }
    }
    public long checkExpiredKeys() throws BadParameterException {

        // Just remove if timeToLive has been set before...
        long timeToWake = 0;
        long currentTime = System.currentTimeMillis();
        int counter =0 ;
        Set<Map.Entry<String, ObjectTimeStampPair> >s = valuesMap.entrySet().stream().filter(a-> a.getValue().getTtl()!=0).collect(Collectors.toSet());
        for (Map.Entry<String, ObjectTimeStampPair> e : s) {
            long timeItShouldRemove = e.getValue().getTtl();
            if ((currentTime ) >= timeItShouldRemove) {
                remove(e.getKey());
            }else {// we need to take the minimum for the while loop everything here is bigger than current time i need to find the minumum
                if (counter == 0 ){ // if it is the first element take it
                    timeToWake = e.getValue().getTtl();
                    counter ++;
                }
                else if (timeToWake > timeItShouldRemove){
                    timeToWake = timeItShouldRemove;
                }

            }
        }
        long result = timeToWake !=0 ? timeToWake -currentTime : 0 ;
        //System.out.print("the time to wake is " +  timeToWake + " the current time is " + currentTime + " and the result is " +   result);
        return result;

//

    }

我的问题是 while(true) 效率不高,尤其是当地图为空或充满无限 ttl 的对象时。

【问题讨论】:

  • 您好,欢迎来到 Stackoverflow! :-) 您注意到,使用 while(true) 可能效率低下。但你的实际问题是什么?您可以使用哪些其他技术来提高效率?

标签: java multithreading hashmap


【解决方案1】:

看起来像延迟队列的用例。这是 BlockingQueue 的一个实现。

BlockingQueue 将阻塞从队列中读取的线程,直到元素出现。

有关 BlockingQueue 的非常好的解释,请参阅 https://youtu.be/d3xb1Nj88pw

DelayQueue 是一种特殊的 BlockingQueue,其中队列中的元素仅在延迟到期时对读取线程可见。

https://howtodoinjava.com/java/multi-threading/java-delayqueue/

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
【解决方案2】:

我觉得用一个线程连续检查不是很好的设计(使用while true),会消耗很多资源。

可以考虑另一种实现方式:内部使用一个timer,比如一个ScheduledExecutorService,在插入数据的同时启动一个定时任务。比如一个key的存活时间是5秒,那么启动一个5秒后要执行的任务来删除这个key。

你可以看看expiringmap

编辑,一般有这几种方式,来自Java time-based map/cache with expiring keys

A.每次使用此地图时执行清理操作。例如,一个线程调用map#size()map#get()map.put()。另外,可以使用另一个DelayQueue,效率会更高。 参考:https://gist.github.com/pcan/16faf4e59942678377e0PassiveExpiringMap

B.每次检查后使用看门狗检查,sleep 一段时间。 参考:apache#mina-org.apache.mina.util.ExpiringMap.

C.使用timer: expiringmap

【讨论】:

  • 如果有人在我安排线程后更改了 ttl 会发生什么?
  • 我不太明白你的意思,我编辑了答案,希望对您有所帮助
  • 我想使用 ScheduledExecutorService 解决方案,但我注意到一个极端情况,我输入了一个带有 ttl 为 1000 msc 的键 X 的对象,然后我输入了带有 ttl 30000 的键 X 但调度程序ttl 1000 的 1000 仍将在 1000 msc 后执行...我的解决方案是在映射键被覆盖时取消预定线程
  • 是的,您需要取消并重新安排
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 2012-05-22
  • 2019-08-15
  • 1970-01-01
相关资源
最近更新 更多