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

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

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

问题

以下是您要翻译的内容:

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

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

线程类:

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

private Map<String, ClientSession> tokensMap;

public ClientSessionCleaner() {
    /*空*/
}

@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);
        }
    });
}

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

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<>();
    }
}

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

英文:

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:

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

private Map&lt;String, ClientSession&gt; tokensMap;

public ClientSessionCleaner() {
    /*Empty*/
}

@Autowired
public ClientSessionCleaner(@Qualifier(&quot;tokens&quot;) Map&lt;String, ClientSession&gt; tokensMap) {
    this.tokensMap = tokensMap;
}

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

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

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

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

}

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

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

The tokens map:

@Configuration
public class RestConfiguration {

    @Bean(name = &quot;tokens&quot;)
    public Map&lt;String, ClientSession&gt; tokensMap() {
        return new HashMap&lt;&gt;();
    }

}

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,因为它们支持带有 基于时间的过期策略 的映射,而这似乎是你想要实现的目标。

LoadingCache<String, ClientSession> tokensMap = Caffeine.newBuilder()
    .expireAfterAccess(10, TimeUnit.SECONDS)
    .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.

LoadingCache&lt;String, ClientSession&gt; tokensMap = Caffeine.newBuilder()
    .expireAfterAccess(10, TimeUnit.SECONDS)
    .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:

确定