[英]Java Filter Lock Implementation Hangs
我已經實現了Java過濾器鎖定,如下所示:
public class Filter implements Lock {
int[] level;
int[] victim;
int n;
public Filter(int n) {
this.n = n;
level = new int[n];
victim = new int[n];
}
@Override
public void lock() {
int me = ConcurrencyUtils.getCurrentThreadId();
for (int i = 1; i < n; i++) {
level[me] = i;
victim[i] = me;
boolean conflicts = true;
while (conflicts) {
conflicts = false;
for (int k = 0; k < n; k++) {
if (k != me && level[k] >= i && victim[i] == me) {
conflicts = true;
break;
}
}
}
}
}
@Override
public void unlock() {
int me = ConcurrencyUtils.getCurrentThreadId();
level[me] = 0;
}
...
}
n
和ConcurrencyUtils.getCurrentThreadId()
返回自定義線程ID(線程最終將具有從0開始的ID)。
這是我的自定義計數器(如類),用於比較實現可運行的性能:
public long getAndIncrement() {
long temp;
lock.lock();
try {
if (value >= maxNumber) {
return value;
}
temp = value;
value = temp + 1;
} finally {
lock.unlock();
}
return temp;
}
@Override
public void run() {
while (getAndIncrement() < maxNumber) {
//do nothing
}
}
這是來自我的AlgorithmRunner類的性能比較部分:
Thread[] threads = new Thread[threadCount];
long threadNumber = 0;
long startTime = System.nanoTime();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(counter);
threads[i].setName(String.valueOf(threadNumber++));
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
long finishTime = System.nanoTime();
return TimeUnit.NANOSECONDS.toMillis(finishTime - startTime);
每當我以大於3的線程號運行它時,它就會掛起。 我的意思是它循環了很長時間(可能是無限的),實際上並沒有掛起。 它在鎖定循環內運行。 鎖定方法似乎有問題(當我將線程睡眠置於鎖定狀態時,我可以看到它最多可以運行5個線程)。
但是,少於3可以。我將自定義鎖與Java的ReentrantLock按性能進行比較。 即使在平時有更多線程的情況下,它也可以在短時間內完成所有操作。
我在實現過程中錯過了什么?
PS 1:我的示例遵循《多處理藝術》。
PS 2:這是掛起時的線程轉儲:
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.60-b09 mixed mode):
"2" prio=10 tid=0x00007f4c6837f000 nid=0x76ff runnable [0x00007f4c4dc8a000]
java.lang.Thread.State: RUNNABLE
at org.oocp.filter.Filter.lock(Filter.java:33)
at org.oocp.Counter.getAndIncrement(Counter.java:50)
at org.oocp.Counter.run(Counter.java:65)
at java.lang.Thread.run(Thread.java:745)
"1" prio=10 tid=0x00007f4c68379000 nid=0x76fe runnable [0x00007f4c4db89000]
java.lang.Thread.State: RUNNABLE
at org.oocp.filter.Filter.lock(Filter.java:33)
at org.oocp.Counter.getAndIncrement(Counter.java:50)
at org.oocp.Counter.run(Counter.java:65)
at java.lang.Thread.run(Thread.java:745)
"0" prio=10 tid=0x00007f4c68378800 nid=0x76fd runnable [0x00007f4c4dd8b000]
java.lang.Thread.State: RUNNABLE
at org.oocp.filter.Filter.lock(Filter.java:33)
at org.oocp.Counter.getAndIncrement(Counter.java:50)
at org.oocp.Counter.run(Counter.java:65)
at java.lang.Thread.run(Thread.java:745)
"Service Thread" daemon prio=10 tid=0x00007f4c681e6800 nid=0x7608 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" daemon prio=10 tid=0x00007f4c681e4000 nid=0x7607 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" daemon prio=10 tid=0x00007f4c681e1000 nid=0x7606 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=10 tid=0x00007f4c681df800 nid=0x7605 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=10 tid=0x00007f4c681bf800 nid=0x7604 in Object.wait() [0x00007f4c4efee000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007db310398> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
- locked <0x00000007db310398> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" daemon prio=10 tid=0x00007f4c681bd800 nid=0x7603 in Object.wait() [0x00007f4c4f0ef000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007db310440> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
- locked <0x00000007db310440> (a java.lang.ref.Reference$Lock)
"main" prio=10 tid=0x00007f4c68009800 nid=0x75f9 in Object.wait() [0x00007f4c701c4000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007d7014ad0> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1281)
- locked <0x00000007d7014ad0> (a java.lang.Thread)
at java.lang.Thread.join(Thread.java:1355)
at org.oocp.AlgorithmRunner.runTest(AlgorithmRunner.java:45)
at org.oocp.AlgorithmRunner.runStatistics(AlgorithmRunner.java:63)
at org.oocp.AlgorithmRunner.main(AlgorithmRunner.java:24)
"VM Thread" prio=10 tid=0x00007f4c681b9000 nid=0x7602 runnable
"GC task thread#0 (ParallelGC)" prio=10 tid=0x00007f4c6801f800 nid=0x75fa runnable
"GC task thread#1 (ParallelGC)" prio=10 tid=0x00007f4c68021800 nid=0x75fb runnable
"GC task thread#2 (ParallelGC)" prio=10 tid=0x00007f4c68023000 nid=0x75fc runnable
"GC task thread#3 (ParallelGC)" prio=10 tid=0x00007f4c68025000 nid=0x75fd runnable
"GC task thread#4 (ParallelGC)" prio=10 tid=0x00007f4c68027000 nid=0x75fe runnable
"GC task thread#5 (ParallelGC)" prio=10 tid=0x00007f4c68029000 nid=0x75ff runnable
"GC task thread#6 (ParallelGC)" prio=10 tid=0x00007f4c6802a800 nid=0x7600 runnable
"GC task thread#7 (ParallelGC)" prio=10 tid=0x00007f4c6802c800 nid=0x7601 runnable
"VM Periodic Task Thread" prio=10 tid=0x00007f4c681f1000 nid=0x7609 waiting on condition
JNI global references: 236
Heap
PSYoungGen total 68608K, used 22516K [0x00000007d7000000, 0x00000007db800000, 0x0000000800000000)
eden space 63488K, 33% used [0x00000007d7000000,0x00000007d84f5308,0x00000007dae00000)
from space 5120K, 20% used [0x00000007db300000,0x00000007db408010,0x00000007db800000)
to space 5120K, 0% used [0x00000007dae00000,0x00000007dae00000,0x00000007db300000)
ParOldGen total 83968K, used 16K [0x0000000785000000, 0x000000078a200000, 0x00000007d7000000)
object space 83968K, 0% used [0x0000000785000000,0x0000000785004000,0x000000078a200000)
PSPermGen total 21504K, used 6588K [0x000000077fe00000, 0x0000000781300000, 0x0000000785000000)
object space 21504K, 30% used [0x000000077fe00000,0x000000078046f0c0,0x0000000781300000)
我可以找到問題所在。 關鍵是:
當讀寫共享對象的字段時,Java編程語言不保證線性化甚至順序一致性[1]。
因此,對於我的關卡和受害者數組,我使用了AtomicInteger而不是int:
AtomicInteger[] level;
AtomicInteger[] victim;
[1]多處理器編程的藝術。 莫里斯·赫利希(Maurice Herlihy),《尼爾·沙維特》(Nir Shavit),2008年,第61頁。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.