3

请在下面找到我创建并打算用作自过期对象的类。

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

任何人都可以提出更好的选择吗?

想在规则引擎中使用它来处理事件。其中一种情况是在收到事件时,将它们放入会话中(使用具有自过期属性的对象)。我希望他们仅根据规则中设置的有效性参加会议。一旦它们过期,它们将从会话中删除。

4

5 回答 5

7

只需懒惰地计算到期时间:

private long expiryDate; // set in constructor

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

无需产生线程。

于 2013-08-06T09:16:08.483 回答
6

每个 Timer 创建一个线程,这是一个非常昂贵的对象。我建议你只在对象中有过期时间,并有一个定期删除过期对象的线程。

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

监控这些项目的线程可以在过期时更新 Drools。

于 2013-08-06T09:17:59.780 回答
4

Apache Collections PassiveExpiringMap值得一看。

于 2013-08-06T09:17:58.737 回答
3

您可以简单地使用时间戳来代替计时器:

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;
    }
}
于 2013-08-06T09:16:47.627 回答
2
  • 如果您有许多事件,则为每个事件创建一个 Timer 效率不会很高。
  • ScheduledExecutor往往更健壮。
  • 您的代码不是线程安全的,isExpired在 Timer 运行后调用的代码可能仍会看到false- 最简单的方法是标记变量volatile

所以你的类可能看起来像这样(尽管我更喜欢另一种建议的方法来完全删除线程并使用时间戳):

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

创建 ScheduledExecutorService:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(poolSize);
于 2013-08-06T09:19:33.483 回答