Avinadav
Avinadav

Reputation: 35

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

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

Answers (2)

Rany Albeg Wein
Rany Albeg Wein

Reputation: 3474

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

Upvotes: 1

Martin Devillers
Martin Devillers

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

Related Questions