public void add(final K key) {
        Future<?> future=timer.schedule(new Runnable() {
            public void run() {
                if(handler != null) {
                    try {
                        handler.expired(key);
                    }
                    catch(Throwable t) {
                    }
                }
                Future<?> tmp=map.remove(key);
                if(tmp != null)
                    tmp.cancel(true);
            }

            public String toString() {
                return "AgeOutCache (timeout=" + timeout +
                  ", handler=" + (handler != null? handler.getClass().getSimpleName() : null) + ")";
            }
        }, timeout, TimeUnit.MILLISECONDS, false); // this task never blocks
        Future<?> result=map.putIfAbsent(key, future);
        if(result != null)
            future.cancel(true);
    }