All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.phantomthief.util.MoreSuppliers Maven / Gradle / Ivy

The newest version!
package com.github.phantomthief.util;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Uninterruptibles.awaitUninterruptibly;
import static java.lang.System.nanoTime;
import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;
import static java.util.concurrent.TimeUnit.NANOSECONDS;

import java.io.Serializable;
import java.time.Duration;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.function.Function;
import java.util.function.Supplier;

import javax.annotation.Nullable;

/**
 * MoreSuppliers增强工具
 * 

{@link Supplier}的增强函数,使{@link Supplier}执行的执行结果被缓存,真正的调用只执行一次。

* * @author w.vela */ public final class MoreSuppliers { /** * 提供器懒加载工具 *

增强{@link Supplier},首次获取值时通过{@link Supplier}加载值,并缓存这个值,在后续获取时直接返回这个缓存的值。

* * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,与原提供器兼容 */ public static CloseableSupplier lazy(Supplier delegate) { return lazy(delegate, true); } /** * 提供器懒加载工具,支持指定是否释放缓存对象 * * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param resetAfterClose 在关闭提供器返回的资源后,是否释放缓存的对象 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,与原提供器兼容 * @see MoreSuppliers#lazy(java.util.function.Supplier) */ public static CloseableSupplier lazy(Supplier delegate, boolean resetAfterClose) { if (delegate instanceof CloseableSupplier) { return (CloseableSupplier) delegate; } else { return new CloseableSupplier<>(checkNotNull(delegate), resetAfterClose); } } /** * 提供器懒加载工具,支持异常类型声明 * * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param 提供值的泛型类型 * @param 加载异常泛型类型 * @return 返回一个懒加载的提供器,与原提供器兼容 */ public static CloseableThrowableSupplier lazyEx(ThrowableSupplier delegate) { return lazyEx(delegate, true); } /** * 提供器懒加载工具,支持异常类型声明和指定是否释放缓存对象 * * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param resetAfterClose 在关闭提供器返回的资源后,是否释放缓存的对象 * @param 提供值的泛型类型 * @param 加载异常泛型类型 * @return 返回一个懒加载的提供器,与原提供器兼容 */ public static CloseableThrowableSupplier lazyEx(ThrowableSupplier delegate, boolean resetAfterClose) { if (delegate instanceof CloseableThrowableSupplier) { return (CloseableThrowableSupplier) delegate; } else { return new CloseableThrowableSupplier<>(checkNotNull(delegate), resetAfterClose); } } /** * 已废弃:使用异步线程加载的提供器懒加载工具 *

请使用{@link #asyncLazyEx(Supplier, Supplier, String)}替代本方法

* * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param pendingSupplier 当超过指定的时间没有获取初始值成功时,使用此提供器提供的值作为托底。此值不会缓存,不影响下次获取时再次尝试初始化 * @param threadName 用于异步初始化的线程名称 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,与原提供器兼容 */ @Deprecated public static Supplier asyncLazy(Supplier delegate, Supplier pendingSupplier, String threadName) { return new AsyncSupplier<>(delegate, pendingSupplier, threadName); } /** * 已废弃:使用异步线程加载的提供器懒加载工具 *

请使用{@link #asyncLazyEx(Supplier, String)}替代本方法

* * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param threadName 用于异步初始化的线程名称 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,与原提供器兼容 */ @Deprecated public static Supplier asyncLazy(Supplier delegate, String threadName) { return asyncLazy(delegate, () -> null, threadName); } /** * 已废弃:使用异步线程加载的提供器懒加载工具 *

请使用{@link #asyncLazyEx(Supplier)}替代本方法

* * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,与原提供器兼容 */ @Deprecated public static Supplier asyncLazy(Supplier delegate) { return asyncLazy(delegate, null); } /** * 使用异步线程加载的提供器懒加载工具 * * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param pendingSupplier 当超过指定的时间没有获取初始值成功时,使用此提供器提供的值作为托底。此值不会缓存,不影响下次获取时再次尝试初始化 * @param threadName 用于异步初始化的线程名称 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,可通过{@link AsyncSupplier#get(java.time.Duration)}方法实现获取超时 */ public static AsyncSupplier asyncLazyEx(Supplier delegate, Supplier pendingSupplier, String threadName) { return new AsyncSupplier<>(delegate, pendingSupplier, threadName); } /** * 使用异步线程加载的提供器懒加载工具 * * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param threadName 用于异步初始化的线程名称 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,可通过{@link AsyncSupplier#get(java.time.Duration)}方法实现获取超时 */ public static AsyncSupplier asyncLazyEx(Supplier delegate, String threadName) { return asyncLazyEx(delegate, () -> null, threadName); } /** * 使用异步线程加载的提供器懒加载工具 * * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载,不能为空 * @param 提供值的泛型类型 * @return 返回一个懒加载的提供器,可通过{@link AsyncSupplier#get(java.time.Duration)}方法实现获取超时 */ public static AsyncSupplier asyncLazyEx(Supplier delegate) { return asyncLazyEx(delegate, null); } /** * 可关闭的Supplier实现 *

支持通过{@link CloseableSupplier#tryClose(com.github.phantomthief.util.ThrowableConsumer)}关闭提供的资源

* * @param 提供值的泛型 */ public static class CloseableSupplier implements Supplier, Serializable { private static final long serialVersionUID = 0L; /** * 原始{@link Supplier}对象,用于提供值的首次加载 */ private final Supplier delegate; /** * 是否在执行{@link #tryClose()}操作时释放缓存的对象 */ private final boolean resetAfterClose; /** * 当前是否已经获取过提供器的值 */ private transient volatile boolean initialized; /** * 当前缓存的提供器的值 */ private transient T value; /** * 构造方法:创建一个CloseableSupplier * * @param delegate 原始{@link Supplier}对象,用于提供值的首次加载 * @param resetAfterClose 是否在执行{@link #tryClose()}操作时释放缓存的对象 */ private CloseableSupplier(Supplier delegate, boolean resetAfterClose) { this.delegate = delegate; this.resetAfterClose = resetAfterClose; } /** * 获取当前值 *

如果当前值没有获取过,将通过{@link #delegate}提供器加载一次获取值,如果获取过,则直接返回上次获取的值

* * @return 提供器的值 */ public T get() { if (!(this.initialized)) { synchronized (this) { if (!(this.initialized)) { T t = this.delegate.get(); this.value = t; this.initialized = true; return t; } } } return this.value; } /** * 返回当前提供器是否获取过初始值 * * @return 是否获取过初始值 */ public boolean isInitialized() { return initialized; } /** * 使用当前缓存的值 * * @param consumer 当前值的消费函数,不能为空 * @param 消费异常泛型 * @throws X 消费抛出的异常 */ public void ifPresent(ThrowableConsumer consumer) throws X { synchronized (this) { if (initialized && this.value != null) { consumer.accept(this.value); } } } /** * 将当前初始化的值转换类型并返回 * * @param mapper 类型映射器,不能为空 * @param 目标类型泛型 * @return 转换值的容器 */ public Optional map(Function mapper) { checkNotNull(mapper); synchronized (this) { if (initialized && this.value != null) { return ofNullable(mapper.apply(value)); } else { return empty(); } } } /** * 尝试释放当前缓存的值,是否真正执行释放取决于{@link #resetAfterClose}属性 */ public void tryClose() { tryClose(i -> { }); } /** * 尝试释放当前缓存的值,是否真正执行释放取决于{@link #resetAfterClose}属性,在释放前执行一个函数以帮助销毁资源等操作 * * @param close 关闭函数,用于销毁资源等操作 * @param 关闭时产生的异常的泛型 * @throws X 关闭时产生的异常 */ public void tryClose(ThrowableConsumer close) throws X { synchronized (this) { if (initialized) { close.accept(value); if (resetAfterClose) { this.value = null; initialized = false; } } } } public String toString() { if (initialized) { return "MoreSuppliers.lazy(" + get() + ")"; } else { return "MoreSuppliers.lazy(" + this.delegate + ")"; } } } /** * 支持操作异常声明的可关闭的Supplier实现 * * @param 提供值泛型 * @param 操作异常泛型 */ public static class CloseableThrowableSupplier implements ThrowableSupplier, Serializable { private static final long serialVersionUID = 0L; /** * 原始{@link ThrowableSupplier}对象,用于提供值的首次加载的值 */ private final ThrowableSupplier delegate; /** * 是否在执行{@link #tryClose()}操作时释放缓存的对象 */ private final boolean resetAfterClose; /** * 当前是否已经获取过提供器的值 */ private transient volatile boolean initialized; /** * 当前缓存的提供器的值 */ private transient T value; /** * 构造方法:创建一个CloseableThrowableSupplier * * @param delegate 原始{@link ThrowableSupplier}对象,用于提供值的首次加载 * @param resetAfterClose 是否在执行{@link #tryClose()}操作时释放缓存的对象 */ private CloseableThrowableSupplier(ThrowableSupplier delegate, boolean resetAfterClose) { this.delegate = delegate; this.resetAfterClose = resetAfterClose; } /** * 获取当前值 *

如果当前值没有获取过,将通过{@link #delegate}提供器加载一次获取值,如果获取过,则直接返回上次获取的值

* * @return 提供器的值 */ public T get() throws X { if (!(this.initialized)) { synchronized (this) { if (!(this.initialized)) { T t = this.delegate.get(); this.value = t; this.initialized = true; return t; } } } return this.value; } /** * 返回当前提供器是否获取过初始值 * * @return 是否获取过初始值 */ public boolean isInitialized() { return initialized; } /** * 使用当前缓存的值 * * @param consumer 当前值的消费函数,不能为空 * @param 消费异常泛型 * @throws X2 消费抛出的异常 */ public void ifPresent(ThrowableConsumer consumer) throws X2 { synchronized (this) { if (initialized && this.value != null) { consumer.accept(this.value); } } } /** * 将当前初始化的值转换类型并返回 * * @param mapper 类型映射器,不能为空 * @param 目标类型泛型 * @return 转换值的容器 */ public Optional map(Function mapper) { checkNotNull(mapper); synchronized (this) { if (initialized && this.value != null) { return ofNullable(mapper.apply(value)); } else { return empty(); } } } /** * 尝试释放当前缓存的值,是否真正执行释放取决于{@link #resetAfterClose}属性 */ public void tryClose() { tryClose(i -> { }); } /** * 尝试释放当前缓存的值,是否真正执行释放取决于{@link #resetAfterClose}属性,在释放前执行一个函数以帮助销毁资源等操作 * * @param close 关闭函数,用于销毁资源等操作 * @param 关闭时产生的异常的泛型 * @throws X2 关闭时产生的异常 */ public void tryClose(ThrowableConsumer close) throws X2 { synchronized (this) { if (initialized) { close.accept(value); if (resetAfterClose) { this.value = null; initialized = false; } } } } public String toString() { if (initialized) { try { return "MoreSuppliers.lazy(" + get() + ")"; } catch (Throwable x) { throw new RuntimeException(x); } } else { return "MoreSuppliers.lazy(" + this.delegate + ")"; } } } /** * 异步加载的提供器实现,通过异步线程来完成初始化操作,支持超时 * * @param 提供值的泛型 */ public static final class AsyncSupplier implements Supplier { /** * 执行初始化操作的线程名称 */ private final String initThreadName; /** * 原始{@link Supplier}对象,用于提供值的首次加载 */ private final Supplier innerSupplier; /** * 托底的{@link Supplier}对象,当异步初始化值超时时,通过此提供器获取返回值,此提供器的返回值不会被缓存 */ private final Supplier pendingSupplier; /** * 当前缓存的提供器的值 */ private volatile T value; /** * 当前是否已经初始化 */ private volatile boolean inited; /** * 当前是否正在进行异步初始化 */ private volatile boolean initing; /** * 首次执行初始化的启动时间 */ private volatile long firstInitNano; /** * 用于初始化线程工作状态同步的信号量 */ private volatile CountDownLatch latch; /** * 构造方法:创建AsyncSupplier对象 * * @param innerSupplier 原始{@link ThrowableSupplier}对象,用于提供值的首次加载 * @param pendingSupplier 托底的{@link Supplier}对象,当异步初始化值超时时,通过此提供器获取返回值,此提供器的返回值不会被缓存 * @param initThreadName 执行初始化操作的线程名称 */ AsyncSupplier(Supplier innerSupplier, Supplier pendingSupplier, String initThreadName) { this.initThreadName = initThreadName; this.innerSupplier = checkNotNull(innerSupplier); this.pendingSupplier = checkNotNull(pendingSupplier); } /** * 获取当前值,支持设置超时时间 *

如果当前值没有获取过,将通过{@link #innerSupplier}提供器加载一次获取值,如果获取过,则直接返回上次获取的值; * 如果获取操作超过指定等待的获取时间,则直接通过{@link #pendingSupplier}获取托底值

* * @param timeoutFromFirstIniting 等待获取的超时时间,获取时间从首次开始执行异步获取算起, * 传入null将不等待,如果初始化成功返回初始化的值,否则返回托底值 */ public T get(@Nullable Duration timeoutFromFirstIniting) { if (inited) { return value; } if (initing) { tryWait(timeoutFromFirstIniting); if (inited) { return value; } return pendingSupplier.get(); } synchronized (this) { if (inited) { return value; } if (initing) { tryWait(timeoutFromFirstIniting); if (inited) { return value; } return pendingSupplier.get(); } // start init firstInitNano = nanoTime(); latch = new CountDownLatch(1); initing = true; Runnable initWithTry = () -> { try { value = innerSupplier.get(); inited = true; initing = false; } catch (Throwable e) { initing = false; throw e; } finally { latch.countDown(); } }; if (initThreadName == null) { new Thread(initWithTry).start(); } else { new Thread(initWithTry, initThreadName).start(); } } if (inited) { return value; } else { tryWait(timeoutFromFirstIniting); if (inited) { return value; } return pendingSupplier.get(); } } /** * 直接获取当前加载的值,不进行等待 * * @see AsyncSupplier#get(java.time.Duration) */ @Override public T get() { return get(null); } /** * 等待指定的时间完成异步加载 * * @param maxWaitFromFirstCall 等待时长 */ private void tryWait(@Nullable Duration maxWaitFromFirstCall) { if (maxWaitFromFirstCall == null) { return; } long passedDuration = nanoTime() - firstInitNano; long maxWaitDuration = maxWaitFromFirstCall.toNanos(); long needWaitDuration = maxWaitDuration - passedDuration; if (needWaitDuration > 0) { awaitUninterruptibly(latch, needWaitDuration, NANOSECONDS); } } } }