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'变量的用途是什么? –