java缓存 单例_定时加载的单例缓存 - Acce1erator的个人空间 - OSCHINA - 中文开源技术交流社区...

import com.google.common.base.Preconditions;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;

import javax.annotation.concurrent.ThreadSafe;

import java.io.Serializable;

import java.util.concurrent.TimeUnit;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

import java.util.function.Supplier;

/**

* Created by zhaoyy on 2017/7/17.

*/

@ThreadSafe

public final class SingletonCache implements Supplier {

private static final AtomicIntegerFieldUpdater STATE_UPDATER =

AtomicIntegerFieldUpdater.newUpdater(SingletonCache.class, "state");

private static final AtomicIntegerFieldUpdater RETRY_UPDATER =

AtomicIntegerFieldUpdater.newUpdater(SingletonCache.class, "retry");

private static final Logger logger = LoggerFactory.getLogger(SingletonCache.class);

private static final int NOT_LOADING = 0;

private static final int LOADING = 1;

//null is NOT permitted

private final SingletonLoader loader;

private final long expiredTimeMills;

private final int maxRetry;

private volatile int state = NOT_LOADING;

private volatile int retry = 0;

private volatile T value = null;

private volatile long lastUpdateTime = -1;

private SingletonCache(SingletonLoader loader, long expiredTimeMills, T defaultValue, int maxRetry) {

this.loader = loader;

this.expiredTimeMills = expiredTimeMills;

this.value = defaultValue;

this.maxRetry = maxRetry;

}

public static Builder builder() {

return new Builder<>();

}

@Nonnull

@Override

public T get() {

if (value == null) {

synchronized (this) {

if (value == null) {

state = LOADING;

updateValueSync();

}

}

} else {

if ((System.currentTimeMillis() - lastUpdateTime > expiredTimeMills)

&& STATE_UPDATER.compareAndSet(this, NOT_LOADING, LOADING)) {

updateValueAsync();

}

}

return value;

}

private void updateValueSync() {

final T newValue;

try {

newValue = loader.load(value);

} catch (Exception e) {

throw new IllegalArgumentException(e);

}

if (newValue == null)

throw new NullPointerException("null value is not permitted!");

updateValueAndReleaseLock(newValue);

}

private void updateValueAndReleaseLock(T value) {

this.value = value;

lastUpdateTime = System.currentTimeMillis();

retry = 0;

state = NOT_LOADING;

}

private void updateValueAsync() {

Thread thread = new Thread(this::loadValueRejectNull, "singleton-cache-async-runner");

thread.start();

}

private void loadValueRejectNull() {

final T newValue;

try {

newValue = loader.load(this.value);

} catch (Exception e) {

logger.error(e.getMessage(), e);

updateRetryUntilMaxRetry();

return;

}

if (newValue == null) {

updateRetryUntilMaxRetry();

return;

}

updateValueAndReleaseLock(newValue);

}

private void updateRetryUntilMaxRetry() {

assert state == LOADING;

if (RETRY_UPDATER.getAndAdd(this, 1) < maxRetry) {

state = NOT_LOADING;

logger.warn("current retry:{}", retry);

return;

}

logger.warn("retry over max times:{}, further update will not execute.", maxRetry);

}

@SuppressWarnings("WeakerAccess")

public static final class Builder {

private long expiredTimeMills = -1;

private T defaultValue = null;

private SingletonLoader loader = null;

private int maxRetry = 5;

public Builder expiredAfter(long duration, TimeUnit unit) {

Preconditions.checkArgument(duration >= 0 && unit != null);

this.expiredTimeMills = unit.toMillis(duration);

return this;

}

public Builder defaultValue(@Nonnull T defaultValue) {

this.defaultValue = defaultValue;

return this;

}

public Builder loader(@Nonnull SingletonLoader loader) {

this.loader = loader;

return this;

}

public Builder maxRetry(int maxRetry) {

this.maxRetry = maxRetry;

return this;

}

public SingletonCache build() {

Preconditions.checkArgument(expiredTimeMills >= 0, "expiredTimeMills < 0!");

Preconditions.checkArgument(loader != null, "null loader!");

Preconditions.checkArgument(maxRetry > 0, "max retry must be a positive number.");

return new SingletonCache<>(loader, expiredTimeMills, defaultValue, maxRetry);

}

}

}

import javax.annotation.Nullable;

import java.io.Serializable;

/**

* Created by zhaoyy on 2017/10/27.

*/

@FunctionalInterface

public interface SingletonLoader {

//T is expected as immutable or effectively immutable

T load(@Nullable T oldValue) throws Exception;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值