第四版 Critical sections部分:
You can also use explicit Lock objects to create critical sections:
[code="java"]//: concurrency/ExplicitCriticalSection.java
// Using explicit Lock objects to create critical sections.
package concurrency;
import java.util.concurrent.locks.*;
// Synchronize the entire method:
class ExplicitPairManager1 extends PairManager {
private Lock lock = new ReentrantLock();
public synchronized void increment() {
lock.lock();
try {
p.incrementX();
p.incrementY();
store(getPair());
} finally {
lock.unlock();
}
}
// Use a critical section:
class ExplicitPairManager2 extends PairManager {
private Lock lock = new ReentrantLock();
public void increment() {
Pair temp;
lock.lock();
try {
p.incrementX();
p.incrementY();
temp = getPair();
} finally {
lock.unlock();
}
store(temp);
}
}
public class ExplicitCriticalSection {
public static void main(String[] args) throws Exception {
PairManager
pman1 = new ExplicitPairManager1(),
pman2 = new ExplicitPairManager2();
CriticalSection.testApproaches(pman1, pman2);
}
} /* Output: (Sample)
pm1: Pair: x: 15, y: 15 checkCounter = 174035
pm2: Pair: x: 16, y: 16 checkCounter = 2608588
*///:~
[/code]
这段代码书里的,只是把synchronized 换成lock 实现,但是 我的运行结果每次会出现:
[color=red]---------- JAVA ----------
Exception in thread "pool-1-thread-4" Pair$PairValuesNotEqualException: Pair values not equal: x: 2, y: 1
at Pair.checkState(ExplicitCriticalSection.java:32)
at PairChecker.run(CriticalSection.java:101)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)[/color]
pm1: Pair: x: 11, y: 11 checkCounter = 3134
pm2: Pair: x: 12, y: 12 checkCounter = 1388632
谁能告诉我问什么这里有异常吗?按书里说是不会的!
哇 这个问题javaeye里居然有人问过,但没人回,郁闷啊,我问题跟他一摸一样[url=/topic/221693]http://www.iteye.com/topic/221693[/url]
这个问题的确比较迷惑人,作为老手我也足足想了1个多小时。
1. 经过调试,发现出现异常的是ExplicitPairManager2,把pm.getPair().checkState();这段代码捕获下异常,并 System.out.println(pm.getClass().getSimpleName());即可定位。
比较下和ExplicitPairManager1的区别,1的方法上多了synchronized,其实有了这个关键字,其里面的lock,unlock有些多余,注释掉后运行也正常。
关键就在于synchronized上了,如果仅仅把synchronized当成一把锁来看待,这程序无论如何也会执行时候出现异常。为什么呢?原因如下:
写入x,y的地方在increment方法上,而读取x,y在getPare()方法。理论上来说,要使得x=y,getPare()必须在等待increment执行结束之后被调用才能相等。从ExplicitPairManager2的代码中,可以发现lock只针对increament有效,没有排斥getPare()方法。
但为什么加了synchronized关键字可以和getPare()互斥呢?私下以为java针对synchronized嵌套结构中做了优化,它们共享一把锁。
[code="java"]
public synchronized void increment() {
lock.lock();
try {
p.incrementX();
p.incrementY();
try{
Thread.sleep(1000);
}catch(Exception e){}
store(getPair()); //getPare()也是synchronized
} finally {
lock.unlock();
}
}
[/code]
为了验证猜想,先注释掉Manager2:
//exec.execute(pcheck2);
另外在ExplicitPairManager1的increment代码中加上一段:
[code="java"]
public synchronized void increment() {
lock.lock();
try {
p.incrementX();
p.incrementY();
try{ //确保increment方法长时间持有这把锁
Thread.sleep(10000);
}catch(Exception e){}
store(getPair());
} finally {
lock.unlock();
}
}
[/code]
在PairChecker的run()方法中加上代码:
[code="java"]
public void run() {
while (true) {
pm.checkCounter.incrementAndGet();
try {
pm.getPair().checkState();
System.out.println("check Thread get the lock");
} catch (Exception e) {
e.printStackTrace();
System.out.println(pm.getClass().getSimpleName());
break;
}
}
}
[/code]
根据执行结果,不难发现PairChecker中的pm.getPair()由于ExplicitPairManager1的increment()长时间持有锁,而一直处在等待状态。