0
我現在讀了一本書Thinking in Java,關於關鍵部分的章節,我無法理解一個例子,因爲我收到了本書中沒有描述的例外。示例如下所示:關鍵部分 - 用Java思考的例子
class Pair {
private int x, y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
public Pair() {
this(0, 0);
}
public int getX() { return x; }
public int getY() { return y; }
public void incrementX() { x++; }
public void incrementY() { y++; }
public class PairValuesNotEqualException extends RuntimeException {
public PairValuesNotEqualException() {
super("Values are not equal: " + Pair.this);
}
}
public void checkState() {
if (x != y) {
throw new PairValuesNotEqualException();
}
}
}
abstract class PairManager {
AtomicInteger checkCounter = new AtomicInteger(0);
protected Pair p = new Pair();
public synchronized Pair getPair() {
// Make copies to protect the original
return new Pair(p.getX(), p.getY());
}
public abstract void increment();
}
// synchronization of the whole method
class PairManager1 extends PairManager {
@Override
public synchronized void increment() {
p.incrementX();
p.incrementY();
}
}
// Critical section
class PairManager2 extends PairManager {
@Override
public void increment() {
synchronized (this) {
p.incrementX();
p.incrementY();
}
}
}
class PairManipulator implements Runnable {
private PairManager pairManager;
public PairManipulator(PairManager pairManager) {
this.pairManager = pairManager;
}
@Override
public void run() {
while (true)
pairManager.increment();
}
}
class PairChecker implements Runnable {
private PairManager pairManager;
public PairChecker(PairManager pairManager) {
this.pairManager = pairManager;
}
@Override
public void run() {
while (true) {
pairManager.checkCounter.incrementAndGet();
pairManager.getPair().checkState();
}
}
}
public class CriticalSection {
static void testApproaches(PairManager pman1, PairManager pman2) {
ExecutorService exec = Executors.newCachedThreadPool();
PairManipulator
pm1 = new PairManipulator(pman1),
pm2 = new PairManipulator(pman2);
PairChecker
pcheck1 = new PairChecker(pman1),
pcheck2 = new PairChecker(pman2);
exec.execute(pm1);
exec.execute(pm2);
exec.execute(pcheck1);
exec.execute(pcheck2);
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
System.out.println("InterruptedException");
}
System.out.println("pm1: " + pm1 + "\npm2: " + pm2);
System.exit(0);
}
public static void main(String[] args) {
PairManager
pman1 = new PairManager1(),
pman2 = new PairManager2();
testApproaches(pman1, pman2);
}
}
輸出示例:
pm1: Pair: Pair{x=364, y=364} counter = 471421
pm2: Pair: Pair{x=365, y=365} counter = 1015604598
這個例子無一例外執行。
在上面的例子中,我明白它是如何工作的,但問題在於顯式鎖定的例子。 實例與書中明確鎖定:
class ExplicitPairManager1 extends PairManager {
private Lock lock = new ReentrantLock();
// why synchronized ??
public synchronized void increment() {
lock.lock();
try {
p.incrementX();
p.incrementY();
} finally {
lock.unlock();
}
}
}
class ExplicitPairManager2 extends PairManager {
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
p.incrementX();
p.incrementY();
} finally {
lock.unlock();
}
}
}
public class ExplicitCriticalSection {
public static void main(String[] args) throws Exception {
PairManager
pm1 = new ExplicitPairManager1(),
pm2 = new ExplicitPairManager2();
CriticalSection.testApproaches(pm1, pm2);
}
}
輸出:
Exception in thread "pool-1-thread-4" critical.sections.Pair$PairValuesNotEqualException: Values are not equal: Pair{x=2, y=1}
at critical.sections.Pair.checkState(CriticalSection.java:49)
at critical.sections.PairChecker.run(CriticalSection.java:133)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
pm1: Pair: Pair{x=1024, y=1024} counter = 3
pm2: Pair: Pair{x=1025, y=1025} counter = 1499445
首先我不明白爲什麼筆者使用在ExplicitPairManager1#增量,如果他使用也鎖定對象?這是書中的錯誤嗎?
第二個問題是我不明白爲什麼我得到異常?
錯誤時拋出被扔在:
class PairChecker implements Runnable {
private PairManager pairManager;
public PairChecker(PairManager pairManager) {
this.pairManager = pairManager;
}
@Override
public void run() {
while (true) {
pairManager.checkCounter.incrementAndGet();
pairManager.getPair().checkState(); // here was thrown an exception
}
}
}
爲什麼我excpetions和作者不?這種可能的JVM行爲在不同的系統上有所不同嗎?我使用Ubuntu 16.04 LTS和Java 8.
'storage'變量的用途是什麼? –