import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Date: 14-3-2
*/
public class TestDeadlock{
public static void main(String[] args){
Q q = new Q();
Config config = new Config();
config.setQ(q);
config.setA(new A(config));
config.setB(new B(config));
config.getA().start();
config.getB().start();
}
}
class Config{
private A a;
private B b;
private Q q;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public Q getQ() {
return q;
}
public void setQ(Q q) {
this.q = q;
}
}
class B extends Thread{
private final byte[] lock = new byte[0];
private Q q ;
private Config config;
public B(Config config){
System.out.println("lockB="+lock);
this.config = config;
this.q = config.getQ();
}
public void run(){
try{
int i = 0;
while (true){
synchronized (lock){
if(!q.getQ().isEmpty()){
try {
System.out.println("b waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//dead lock code
i++;
q.getQ().add("B" + i);
System.out.println("thread B put B" + i);
config.getA().notifyA(); //wait A lock,held B lock
}
TimeUnit.SECONDS.sleep(2);
}
}catch (Exception e){
e.printStackTrace();
}
}
public void notifyB(){
synchronized (lock){
System.out.println("A notify B...");
if(q.getQ().isEmpty()){
// synchronized (lock){
lock.notifyAll();
// }
}
}
}
}
class A extends Thread{
private final byte[] lock = new byte[0];
private Q q ;
private Config config;
public A(Config config){
this.q = config.getQ();
this.config = config;
}
public void run(){
try{
while (true){
synchronized (lock){
if(q.getQ().isEmpty()){
try {
System.out.println("a waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//dead lock code
System.out.println("thread a get " + q.get());
if(q.getQ().isEmpty()){
config.getB().notifyB(); //wait B lock,held A lock
}
}
TimeUnit.SECONDS.sleep(2);
}
}catch (Exception e){
e.printStackTrace();
}
}
public void notifyA(){
synchronized (lock){
System.out.println("B notify A...");
if(!this.q.getQ().isEmpty()){
// synchronized (lock){
lock.notifyAll();
// }
}
}
}
}
class Q {
private final BlockingQueue q = new LinkedBlockingQueue();
public void put(Object obj){
q.add(obj);
}
public Object get(){
return q.poll();
}
public Queue getQ(){
return q;
}
}
不小心写了一段死锁代码,dump出来才知道。如注释处,跑了一下发现,A等B的锁,B却也在等A的锁,形成死锁。
典型的过度同步(effective java)。在同步块中调用外来逻辑容易导致异常、死锁、数据损坏。
以上把锁之外的逻辑移出synchronized块,或者改写notifyA/notifyB的逻辑即可。