java面包屑实现_在Java中实现过滤器和面包店锁
java面包屑實現
為了了解鎖的工作原理,實現自定義鎖是一種好方法。 這篇文章將展示如何在Java上實現Filter和Bakery鎖(自旋鎖),并將它們的性能與Java的ReentrantLock進行比較。 過濾器鎖和面包房鎖滿足互斥并且也是無饑餓算法,面包房鎖是先到先服務的鎖[1]。
為了進行性能測試,使用不同的鎖類型,不同的線程數和不同的次數將計數器值遞增到10000000。 測試系統配置為:Intel Core I7(具有8個內核,其中4個是真實的),Ubuntu 14.04 LTS和Java 1.7.0_60。
過濾器鎖具有n-1個級別,可以視為“候診室”。 獲取鎖之前,必須有一個線程穿過此等候室。 級別[2]有兩個重要屬性:
過濾器鎖定的實現如下:
/** * @author Furkan KAMACI */ public class Filter extends AbstractDummyLock implements Lock { /* Due to Java Memory Model, int[] not used for level and victim variables. Java programming language does not guarantee linearizability, or even sequential consistency, when reading or writing fields of shared objects [The Art of Multiprocessor Programming. Maurice Herlihy, Nir Shavit, 2008, pp.61.] */ private AtomicInteger[] level; private AtomicInteger[] victim; private int n; /** * Constructor for Filter lock * * @param n thread count */ public Filter(int n) { this.n = n; level = new AtomicInteger[n]; victim = new AtomicInteger[n]; for (int i = 0; i < n; i++) { level[i] = new AtomicInteger(); victim[i] = new AtomicInteger(); } } /** * Acquires the lock. */ @Override public void lock() { int me = ConcurrencyUtils.getCurrentThreadId(); for (int i = 1; i < n; i++) { level[me].set(i); victim[i].set(me); for (int k = 0; k < n; k++) { while ((k != me) && (level[k].get() >= i && victim[i].get() == me)) { //spin wait } } } } /** * Releases the lock. */ @Override public void unlock() { int me = ConcurrencyUtils.getCurrentThreadId(); level[me].set(0); } }面包店鎖定算法通過使用面包店中經常使用的分布式版本的數字分配機來維護先到先得的屬性:每個線程在門口取一個數字,然后等待,直到沒有嘗試使用更早編號的線程為止輸入[3]。
面包店鎖的實現如下:
/** * @author Furkan KAMACI */ public class Bakery extends AbstractDummyLock implements Lock { /* Due to Java Memory Model, int[] not used for level and victim variables. Java programming language does not guarantee linearizability, or even sequential consistency, when reading or writing fields of shared objects [The Art of Multiprocessor Programming. Maurice Herlihy, Nir Shavit, 2008, pp.61.] */ private AtomicBoolean[] flag; private AtomicInteger[] label; private int n; /** * Constructor for Bakery lock * * @param n thread count */ public Bakery(int n) { this.n = n; flag = new AtomicBoolean[n]; label = new AtomicInteger[n]; for (int i = 0; i < n; i++) { flag[i] = new AtomicBoolean(); label[i] = new AtomicInteger(); } } /** * Acquires the lock. */ @Override public void lock() { int i = ConcurrencyUtils.getCurrentThreadId(); flag[i].set(true); label[i].set(findMaximumElement(label) + 1); for (int k = 0; k < n; k++) { while ((k != i) && flag[k].get() && ((label[k].get() < label[i].get()) || ((label[k].get() == label[i].get()) && k < i))) { //spin wait } } } /** * Releases the lock. */ @Override public void unlock() { flag[ConcurrencyUtils.getCurrentThreadId()].set(false); } /** * Finds maximum element within and {@link java.util.concurrent.atomic.AtomicInteger} array * * @param elementArray element array * @return maximum element */ private int findMaximumElement(AtomicInteger[] elementArray) { int maxValue = Integer.MIN_VALUE; for (AtomicInteger element : elementArray) { if (element.get() > maxValue) { maxValue = element.get(); } } return maxValue; } }對于此類算法,應提供或使用從0或1開始并以一個增量遞增的線程id系統。 線程的名稱為此目的進行了適當設置。 還應該考慮:Java編程語言在讀取或寫入共享對象的字段時不能保證線性化,甚至不能保證順序一致性[4]。 因此,過濾器鎖的級別和受害變量,面包店鎖的標志和標簽變量定義為原子變量。 一方面,想要測試Java內存模型效果的人可以將該變量更改為int []和boolean []并使用兩個以上的線程運行算法。 然后,即使線程仍然存在,也可以看到該算法將針對Filter或Bakery掛起。
為了測試算法性能,實現了一個自定義計數器類,該類具有getAndIncrement方法,如下所示:
/** * gets and increments value up to a maximum number * * @return value before increment if it didn't exceed a defined maximum number. Otherwise returns maximum number. */ public long getAndIncrement() { long temp; lock.lock(); try { if (value >= maxNumber) { return value; } temp = value; value = temp + 1; } finally { lock.unlock(); } return temp; }公平測試多個應用程序配置存在最大的障礙。 考慮的是:有很多工作(將變量遞增到所需數量),并且在線程數量不同的情況下,完成它的速度有多快。 因此,為了進行比較,應該有一個“工作”平等。 此方法還使用該代碼段測試不必要的工作負載:
if (value >= maxNumber) { return value; }比較多個線程時,一種計算線程的單位工作性能的方法(即,不設置最大障礙,在循環中迭代到最大數量,然后將最后一個值除以線程數量)。
此配置用于性能比較:
| 線程數 | 1,2,3,4,5,6,7,8 |
| 重試計數 | 20 |
| 最大人數 | 10000000 |
這是包含標準誤差的結果圖表:
首先,當您在Java中多次運行代碼塊時,會對代碼進行內部優化。 當算法多次運行并且將第一輸出與第二輸出進行比較時,可以看到此優化的效果。 因此,第一經過時間通常應大于第二行。 例如:
currentTry = 0, threadCount = 1, maxNumber = 10000000, lockType = FILTER, elapsedTime = 500 (ms) currentTry = 1, threadCount = 1, maxNumber = 10000000, lockType = FILTER, elapsedTime = 433 (ms)結論
從圖表中可以看出,“面包房鎖”比“過濾器鎖”要快,標準誤差也很小。 原因是篩選器鎖定的鎖定方法。 在Bakery Lock中,作為一種公平的方法,線程是一個一個地運行的,但在Filter Lock中,它們是相互計算的。 與其他Java相比,Java的ReentrantLock具有最佳的性能。
另一方面,Filter Lock線性惡化,但Bakery和ReentrantLock卻沒有(當Lock Lock運行更多線程時,它可能具有線性圖形)。 更多的線程數并不意味著更少的經過時間。 由于創建和鎖定/解鎖線程,所以2個線程可能比1個線程差。 當線程數開始增加時,Bakery和ReentrantLock的經過時間會變得更好。 但是,當線程數持續增加時,它就會變得更糟。 原因是運行算法的測試計算機的真實核心編號。
- 可以從此處下載用于在Java中實現過濾器和面包店鎖的源代碼: https : //github.com/kamaci/filbak
翻譯自: https://www.javacodegeeks.com/2015/05/implementing-filter-and-bakery-locks-in-java.html
java面包屑實現
總結
以上是生活随笔為你收集整理的java面包屑实现_在Java中实现过滤器和面包店锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为智慧屏 V5 Pro 85/98 英
- 下一篇: AMD 23.9.3 BETA 驱动发布