package async.up;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class DelayRetryUtil {
private static DelayQueue<RetryItem> RETRY_DELAY_QUEUE = null;
static boolean offer(RetryItem e) {
// 延迟初始化,因为延迟队列是耗费cpu及内存资源的开销,在真正使用时才进行初始化,并执行任务
// todo 后续可以增加通过其他线程动态监测RETRY_DELAY_QUEUE不再使用时,进行销毁
if(RETRY_DELAY_QUEUE == null) {
synchronized (DelayRetryUtil.class) {
if(RETRY_DELAY_QUEUE == null) {
initConsumer();
}
}
}
return RETRY_DELAY_QUEUE.offer(e);
}
private static void initConsumer() {
RETRY_DELAY_QUEUE = new DelayQueue<>();
new Thread(() -> {
boolean go = true;
while(go) {
try {
RetryItem i = RETRY_DELAY_QUEUE.take();
if(i != null) {
System.out.println("123");
}
} catch (InterruptedException e1) {
go = false;
}
}
}).start();
}
static class RetryItem implements Delayed{
private long startTime;
RetryItem(long startTime) {
this.startTime = startTime;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(startTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
RetryItem c = (RetryItem) o;
return this.startTime - c.startTime > 0 ? 1 : (this.startTime - c.startTime < 0 ? -1 : 0);
}
}
}
上面的程序中,在高并发环境下,return RETRY_DELAY_QUEUE.offer(e); 会不会有NullPointException,以及为什么了?
会不会NullPointException 我不太清楚,但是这种双检锁在单例模式下,需要在对象上加volatile,否则在给对象初始化的时候,可能因为重排序的问题,导致第一个if判断不满足,但是对象本身并不可用。 你可以网上查一查,双检锁的单例模式,必须要加volatile的。
对,你的说法是对的,我们讨论发现了这个问题,但是本地验证的时候没复现,加上volatile就完美了。