阅读更多
package com.asc.mmmu;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
class Cell { // Do not use
private static final Log log=LogFactory.getLog(Cell.class);
private long value;
synchronized long getValue() { return
value; }
synchronized void setValue(long v) {
value = v; }
synchronized void swapValue(Cell other)
{
long t = getValue();
long v = other.getValue();
setValue(v);
other.setValue(t);
}
static class R implements Runnable{
Cell a;
Cell b;
@Override
public void run() {
a=new Cell();
a.setValue(1);
b=new Cell();
b.setValue(2);
for(int i=0;i<100;i++){
try {
log.info("a swap b");
Thread.sleep(10);
} catch (InterruptedException e) {
log.error("sleep erro",e);
}
a.swapValue(b);
try {
log.info("b swap a");
Thread.sleep(10);
} catch (InterruptedException e) {
log.error("sleep erro",e);
}
b.swapValue(a);
}
}
}
public static void deadlock(){
Cell.R r=new Cell.R();
Thread[] a=new Thread[2];
for (int i = 0; i < 2; i++) {
a[i]=new Thread(r);
a[i].start();
}
try {
a[0].join();
} catch (InterruptedException e) {
log.error("sleep error",e);
}
}
public static final void main(String[] args){
log.info("begin");
Cell.deadlock();
log.info("end");
}
}
试验表明: 关键是
1.synchronized void swapValue(Cell other){} 的 synchronized .
2.a.swapValue(b);b.swapValue(a);
这两个条件,同时具备,才会deadlock.
解决:resource ordering
public void swapValue(Cell other) {
if (other == this) // alias check
return;
else if (System.identityHashCode(this) < System.identityHashCode(other))
this.doSwapValue(other);
else
other.doSwapValue(this);
}
protected synchronized void doSwapValue(Cell other) {
// same as original public version:
long t = getValue();
long v = other.getValue();
setValue(v);
other.setValue(t);
}
关键:System.identityHashCode(this) < System.identityHashCode(other)) ,不再deadlock.
另外一个办法:外部lock
class ExternalLock {
public static synchronized void swapCells(Cell cell1, Cell cell2) {
cell1.swapValue(cell2);
}
}