危险:
synchronized (q) {
synchronized (list) {
}
}
有一天你会添加一个方法,或者以这样的顺序调用方法,实际上它也会这样做:
synchronized (list) {
synchronized (q) {
}
}
那么这只是一个死锁定时炸弹。
假设这是一个完整的类,您可以只锁定一个,或者通常synchronized
在方法上锁定对象本身。对这些私有的所有其他访问也需要同步。
public class Tester {
private BlockingQueue<Ticket> q = new LinkedBlockingQueue<>();
private ArrayList<Long> list = new ArrayList<>();
public synchronized void acceptTicket(Ticket p) {
try {
q.put(p);
if (list.size() < 5) {
list.add(p.getSize());
} else {
list.remove(0);
list.add(p.getSize());
}
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
或更清洁:
public class Tester {
private BlockingQueue<Ticket> q = new LinkedBlockingQueue<>();
private ArrayList<Long> list = new ArrayList<>();
public void acceptTicket(Ticket p) {
try {
//this is cleaner, because I don't know what logger class is doing,
//I want to eliminate chance of deadlock and reduce time we are in lock
synchronized (this){
q.put(p);
if (list.size() < 5) {
list.add(p.getSize());
} else {
list.remove(0);
list.add(p.getSize());
}
}
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
更清洁,但在你的情况下不太可能是必要的(根据我所看到的):
public class Tester {
private final Object lockObj = new Object(); //specific object for locking
//could use any other private, non-exposed final but
//this makes it absolutely clear what I should be
//using for locks
private BlockingQueue<Ticket> q = new LinkedBlockingQueue<>();
private ArrayList<Long> list = new ArrayList<>();
public void acceptTicket(Ticket p) {
try {
//"this" can be locked by external code outside my control here,
//so I use a specific private final object lockObj to eliminate deadlocks and
//provide finer grained locking - reducing contension
synchronized (lockObj){
q.put(p);
if (list.size() < 5) {
list.add(p.getSize());
} else {
list.remove(0);
list.add(p.getSize());
}
}
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}