懒惰学习_懒惰评估
懶惰學習
最近,我正在編寫log4j附加程序,并希望在自定義附加程序創建過程中使用logger記錄一些診斷詳細信息,但是log4j初始化僅在創建附加程序實例后才完成,因此在此階段記錄的消息將被忽略。
我感到需要在自定義附加程序中進行延遲初始化,并開始研究選項。 在此博客中,我將分享我嘗試過的事情。
我想到的一件事是Singleton方法,但是現在已知的事實是Singleton會導致測試問題,并且無法擴展它,因此混合并發和對象構造的方法并不是那么好。
如果需要單例,那么最好使用依賴注入框架,而不是破壞應用程序代碼。 讓我們回到延遲初始化/評估。
一些編程語言(例如scala / swift等)支持惰性,因此不需要自定義代碼即可執行此操作,但是在Java空間中,我們仍然必須編寫線程安全的代碼才能正確執行。
讓我們看一下Java中的一些選項以及獲得的性能類型。
–使用同步的蠻力
這是最簡單,效率最低的一種,scala正在使用這種方法。 Scala一個可用@ ScalaLazy.java
public class SingleLock<V> implements Lazy<V> {private Callable<V> codeBlock;private V value;public SingleLock(Callable<V> codeBlock) {this.codeBlock = codeBlock;}@Overridepublic synchronized V get() {if (value == null) {setValue();}return value;}private void setValue() {try {value = codeBlock.call();} catch (Exception e) {throw new RuntimeException(e);}}}–雙鎖
編寫起來并不復雜,并且具有良好的性能。
public class DoubleLock<V> implements Lazy<V> {private Callable<V> codeBlock;private V value;private volatile boolean loaded;public DoubleLock(Callable<V> codeBlock) {this.codeBlock = codeBlock;}@Overridepublic V get() {if (!loaded) {synchronized (this) {if (!loaded) {setValue();loaded = true;}}}return value;}private void setValue() {try {value = codeBlock.call();} catch (Exception e) {throw new RuntimeException(e);}}}–使用未來任務
這種方法易于編寫,并具有良好的性能。
public class LazyFutureTask<V> implements Lazy<V> {private final FutureTask<V> futureTask;public LazyFutureTask(Callable<V> codeBlock) {this.futureTask = new FutureTask<>(codeBlock);}@Overridepublic V get() {futureTask.run();return getValue();}private V getValue() {try {return futureTask.get();} catch (Exception e) {throw new RuntimeException(e);}} }雙鎖方法可提供最佳性能,而蠻力則是最差的。 我使用不同數量的線程對100萬次調用進行了快速基準測試。
| 單鎖性能非常差,讓我們通過刪除單鎖來查看數字,以了解“雙鎖和未來任務”的執行情況。
這些基準測試很快完成,但是詳細的基準測試數字應該接近。 可以在github上獲得此博客文章的代碼 |
翻譯自: https://www.javacodegeeks.com/2016/08/lazy-evaluation.html
懶惰學習
總結
- 上一篇: 你只是看起来很努力_我的方法在这方面看起
- 下一篇: 华为:老机型升级鸿蒙 HarmonyOS