如何在Map<k,v>上创建一个始终运行并且可以从Map中移除键的线程?

huangapple go评论109阅读模式
英文:

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

问题

以下是您要翻译的内容:

我正在编写优惠券系统的REST API,
并且我正在尝试创建一个在线程,该线程在服务器运行时始终工作。

该线程需要在客户端在10秒内未通过控制器类使用服务器时(通过客户端会话)移除令牌+客户端会话。

线程类:

  1. public class ClientSessionCleaner implements Runnable {
  2. private boolean run = true;
  3. private Map<String, ClientSession> tokensMap;
  4. public ClientSessionCleaner() {
  5. /*空*/
  6. }
  7. @Autowired
  8. public ClientSessionCleaner(@Qualifier("tokens") Map<String, ClientSession> tokensMap) {
  9. this.tokensMap = tokensMap;
  10. }
  11. @Override
  12. public void run() {
  13. HashMap<String, ClientSession> copy = new HashMap<>(tokensMap);
  14. do {
  15. CleanMap(copy);
  16. } while (run);
  17. }
  18. private void CleanMap(HashMap<String, ClientSession> copy) {
  19. copy.forEach((k, v) -> {
  20. if (System.currentTimeMillis() - v.getLastAccessMillis() == 10 * 1_000){
  21. copy.remove(k);
  22. }
  23. });
  24. }

我在主类中启动线程,这样可以吗?

  1. public static void main(String[] args) {
  2. SpringApplication.run(CouponSystemApplication.class, args);
  3. ClientSessionCleaner cleaner = new ClientSessionCleaner();
  4. Thread thread = new Thread(cleaner);
  5. thread.start();
  6. }

当我启动服务器时,我收到以下错误:

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

令牌映射:

  1. @Configuration
  2. public class RestConfiguration {
  3. @Bean(name = "tokens")
  4. public Map<String, ClientSession> tokensMap() {
  5. return new HashMap<>();
  6. }
  7. }

我不知道线程代码是否正确(?),以及我应该如何使线程工作。
我对线程不太熟悉,非常感谢您的帮助!

英文:

I'm writing REST API of coupons system,
and I'm trying to create a thread that works all the time that the server is running.

The thread needs to remove the token+client session if the client doesn't use the server (through the controllers class) passes 10 seconds.

The class of the thread:

  1. public class ClientSessionCleaner implements Runnable {
  2. private boolean run = true;
  3. private Map&lt;String, ClientSession&gt; tokensMap;
  4. public ClientSessionCleaner() {
  5. /*Empty*/
  6. }
  7. @Autowired
  8. public ClientSessionCleaner(@Qualifier(&quot;tokens&quot;) Map&lt;String, ClientSession&gt; tokensMap) {
  9. this.tokensMap = tokensMap;
  10. }
  11. @Override
  12. public void run() {
  13. HashMap&lt;String, ClientSession&gt; copy = new HashMap&lt;&gt;(tokensMap);
  14. do {
  15. CleanMap(copy);
  16. }while (run);
  17. }
  18. private void CleanMap(HashMap&lt;String, ClientSession&gt; copy) {
  19. copy.forEach((k, v) -&gt; {
  20. if (System.currentTimeMillis() - v.getLastAccessMillis() == 10 * 1_000){
  21. copy.remove(k);
  22. }
  23. });
  24. }

I'm starting the thread in the main class, it is ok?

  1. public static void main(String[] args) {
  2. SpringApplication.run(CouponSystemApplication.class, args);
  3. ClientSessionCleaner cleaner = new ClientSessionCleaner();
  4. Thread thread =new Thread(cleaner);
  5. thread.start();
  6. }

When I'm starting the server I'm getting this:

  1. Exception in thread &quot;Thread-178&quot; java.lang.NullPointerException
  2. at java.base/java.util.HashMap.putMapEntries(HashMap.java:496)
  3. at java.base/java.util.HashMap.&lt;init&gt;(HashMap.java:485)
  4. at com.Avinadav.couponsystem.rest.login.ClientSessionCleaner.run(ClientSessionCleaner.java:25)
  5. at java.base/java.lang.Thread.run(Thread.java:834)

The tokens map:

  1. @Configuration
  2. public class RestConfiguration {
  3. @Bean(name = &quot;tokens&quot;)
  4. public Map&lt;String, ClientSession&gt; tokensMap() {
  5. return new HashMap&lt;&gt;();
  6. }

}

I don't know if the thread code is ok (?) and what I should do to make the thread work.
I'm new with threads,
thx for all the help!

答案1

得分: 1

如果我理解正确,看起来您正在尝试实现一种清理过期的 ClientSession 的服务。是这样吗?

如果是这样的话,您的 Runnable 实际上可以是一个 @Component,其中 @Scheduled 注解将定义一个定期的过程,用于进行清理。

有关调度的更多信息,请查看Spring 中的 @Scheduled 注解

英文:

If I understand you correctly, it seems like you're trying to implement some kind of a cleanup service for outdated ClientSessions. Is that right?

If so, your Runnable can actually be a @Component in which a @Scheduled annotation will define a periodic procedure in which the cleaning will take place.

For more info about Scheduling, check out the The @Scheduled Annotation in Spring

答案2

得分: 0

你的用例 可能 适用于流行的缓存库,比如 CaffeineGoogle Guava,因为它们支持带有 基于时间的过期策略 的映射,而这似乎是你想要实现的目标。

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

对于更复杂的逻辑,可以使用 LoadingCache#expireAfter。使用这样的库将可以避免你处理复杂的并发问题。

英文:

Your use-case may fit the functionality of a popular caching library like Caffeine or Google Guava, because it has support for maps with time-based eviction and it seems to be me that's what you're trying to accomplish.

  1. LoadingCache&lt;String, ClientSession&gt; tokensMap = Caffeine.newBuilder()
  2. .expireAfterAccess(10, TimeUnit.SECONDS)
  3. .build();

For more complex logic use LoadingCache#expireAfter. Using a library like this will prevent you from having to deal with complex concurrency issues.

huangapple
  • 本文由 发表于 2020年8月24日 19:40:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/63560306.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定