Sudhanshu Umalkar
Sudhanshu Umalkar

Reputation: 4202

Self expiring object - any better alternative

Please find below the class that I have created and intend to use as a self-expiring object.

public class SelfExpiringObject {

    private boolean expired;
    // other properties

    public void setValidity(final int seconds) {
        new Timer().schedule(new TimerTask() {
            public void run() {
                expired = true;
            }
        }, TimeUnit.SECONDS.toMillis(seconds));
    }

    public boolean isExpired() {
        return expired;
    }
}

Any better alternative that anybody can suggest?

Want to use this in a rule engine for processing events. One of the scenarios would be when the events are received, they are put into the session (using object with self-expiring property). I want them to be in the session only as per the validity set up in the rules. Once they expire, they would be removed from the session.

Upvotes: 6

Views: 6743

Answers (5)

matcauthon
matcauthon

Reputation: 2261

The Apache Collections PassiveExpiringMap could worth looking at.

Upvotes: 4

assylias
assylias

Reputation: 328735

  • If you have many events, creating one Timer per event is not going to be very efficient.
  • ScheduledExecutor tend to be more robust.
  • Your code is not thread safe and a code calling isExpired after the Timer has run might still see false - the simplest thing is to mark the variable volatile

So your class could look like this (although I prefer the other proposed approach to remove the threads completely and use timestamps instead):

public class SelfExpiringObject {

    private final ScheduledExecutorService scheduler;
    private volatile boolean expired = false;
    // other properties

    public SelfExpiringObject(ScheduledExecutorService scheduler) {
        this.scheduler = scheduler;
    }

    public void setValidity(final int seconds) {
        scheduler.schedule(new Runnable() {
            public void run() {
                expired = true;
            }
        }, seconds, TimeUnit.SECONDS);
    }

    public boolean isExpired() {
        return expired;
    }
}

To create a ScheduledExecutorService:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(poolSize);

Upvotes: 2

Peter Lawrey
Peter Lawrey

Reputation: 533670

Each Timer creates a thread and this is a very expensive object. I suggest you just have the expiry time in the object and have a thread which periodically removes expired objects.

public class ExpiringObject {

    private long expiresMS;
    // other properties

    public void setValidity(final int seconds) {
        expiresMS = System.currentTimeMillis() + seconds * 1000;
    }

    public boolean isExpired() {
        return System.currentTimeMillis() >= expireMS;
    }
}

The thread which monitors these items can update Drools when it has expired.

Upvotes: 9

Vincent van der Weele
Vincent van der Weele

Reputation: 13177

Instead of a timer, you could simply use timestamps:

public class SelfExpiringObject {
    private long timestamp;

    private boolean expired;
    // other properties

    public void setValidity(final int seconds) {
        timestamp = System.currentTimeMillis() + 1000 * seconds;
    }

    public boolean isExpired() {
        if (!expired) {
            expired = System.currentTimeMillis() >= timestamp;
        } 
        return expired;
    }
}

Upvotes: 3

artbristol
artbristol

Reputation: 32427

Just calculate the expiry lazily:

private long expiryDate; // set in constructor

public boolean isExpired() {
    return System.currentTimeMillis() >= expiryDate;
}

No need to spawn a thread.

Upvotes: 8

Related Questions