synchronized是一个关键字,允许安全地访问代码中的关键部分。它可以用于方法(例如public synchronized void foo())或代码块(synchronized(obj) { ... })。当线程进入synchronized块时,它会获得对象的监视器(锁)。当监视器被占用时,其他线程无法进入另一个使用相同对象作为监视器的synchronized块。
特点:
this、静态对象(例如类)或任意对象进行同步。public class Counter { private int count; private final Object lock = new Object(); // 私有对象 public void increment() { synchronized(lock) { count++; } } }
为什么最好使用私有锁? 因为如果根据公共对象(例如this或公共字符串)进行同步,外部代码也可能会获得这个监视器,从而导致死锁或不正确的工作。
问题: 如果根据包含固定值的String对象进行同步,会发生什么?
答案: 在Java中,字符串是被池化的(相同字面量对应相同对象)。如果根据synchronized("lock")进行同步,可能会意外与其他同步在相同字面量上的代码发生冲突,这将导致程序的不同部分之间意外的锁定。
synchronized("LOCK") { ... }
故事
在一个多线程交易系统中,为同步使用了公共对象,外部代码能够获得锁,导致不同模块的线程之间发生临时死锁,导致交易所停滞。
故事
一位年轻的开发者根据字符串字面量同步对集合的访问。代码的另一部分也根据相同值的字符串进行同步。这些线程排队,导致业务逻辑的显著减慢。
故事
每次同步时选择一个新的对象:
synchronized(new Object()) { ... }。结果是同步根本不工作,多个线程同时访问数据。这只有在压力测试中才能被发现。