如何在 Map<k,v> 上创建一直工作的线程并从地图中删除键?

how to create thread on Map<k,v> that work all the time and remove key from the map?

我正在编写优惠券系统的 REST API, 我正在尝试创建一个线程,该线程在服务器 运行.

期间一直有效

如果客户端不使用服务器(通过控制器class)超过 10 秒,线程需要删除令牌+客户端会话。

线程的class:

public class ClientSessionCleaner implements Runnable {
private boolean run = true;

private Map<String, ClientSession> tokensMap;

public ClientSessionCleaner() {
    /*Empty*/
}

@Autowired
public ClientSessionCleaner(@Qualifier("tokens") Map<String, ClientSession> tokensMap) {
    this.tokensMap = tokensMap;
}

@Override
public void run() {
    HashMap<String, ClientSession> copy = new HashMap<>(tokensMap);
    do {
        CleanMap(copy);
    }while (run);
}

private void CleanMap(HashMap<String, ClientSession> copy) {
    copy.forEach((k, v) -> {
        if (System.currentTimeMillis() - v.getLastAccessMillis() == 10 * 1_000){
            copy.remove(k);
        }
    });
}

我在主线程启动class,可以吗?

    public static void main(String[] args) {
    SpringApplication.run(CouponSystemApplication.class, args);
    ClientSessionCleaner cleaner = new ClientSessionCleaner();
    Thread thread =new Thread(cleaner);
    thread.start();

}

当我启动服务器时,我得到这个:

Exception in thread "Thread-178" java.lang.NullPointerException
at java.base/java.util.HashMap.putMapEntries(HashMap.java:496)
at java.base/java.util.HashMap.<init>(HashMap.java:485)
at com.Avinadav.couponsystem.rest.login.ClientSessionCleaner.run(ClientSessionCleaner.java:25)
at java.base/java.lang.Thread.run(Thread.java:834)

代币地图:

@Configuration
public class RestConfiguration {

    @Bean(name = "tokens")
    public Map<String, ClientSession> tokensMap() {
        return new HashMap<>();
    }

}

我不知道线程代码是否可以(?)以及我应该怎么做才能使线程工作。 我是线程的新手, 谢谢大家的帮助!

您的 use-case 可能 适合像 Caffeine or Google Guava, because it has support for maps with time-based eviction 这样流行的缓存库的功能,而您似乎就是我想要完成的.

LoadingCache<String, ClientSession> tokensMap = Caffeine.newBuilder()
    .expireAfterAccess(10, TimeUnit.SECONDS)
    .build();

对于更复杂的逻辑,请使用 LoadingCache#expireAfter。使用这样的库将使您不必处理复杂的并发问题。

如果我没有理解错的话,您似乎在尝试为过时的 ClientSession 实施某种清理服务。是吗?

如果是这样,您的 Runnable 实际上可以是一个 @Component,其中 @Scheduled 注释将定义一个周期性的清洁过程。

有关日程安排的更多信息,请查看 The @Scheduled Annotation in Spring