Reputation: 35
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<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);
}
});
}
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 "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)
The tokens map:
@Configuration
public class RestConfiguration {
@Bean(name = "tokens")
public Map<String, ClientSession> tokensMap() {
return new HashMap<>();
}
}
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!
Upvotes: 1
Views: 75
Reputation: 3474
If I understand you correctly, it seems like you're trying to implement some kind of a cleanup service for outdated ClientSession
s. 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
Upvotes: 1
Reputation: 18022
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<String, ClientSession> 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.
Upvotes: 0