synchronized 关键字在 Java 支持多线程时出现,用于保证对来自不同线程的代码块或方法的独占访问。历史上,这是 Java 对经典的竞争条件和数据不一致性问题的回应,这些问题发生在多个线程同时访问共享数据时。
问题 在于多线程工作时如何确保操作的“原子性”和防止对象状态的矛盾变化。错误使用 synchronized 可能导致死锁(deadlock)、性能下降,甚至在选择监视对象不当的情况下导致不同步。
解决方案 — 在需保证只有一个线程同时执行该代码块的方法或代码块上使用 synchronized 关键字。应仔细选择同步对象,避免较长的临界区,对于更复杂的任务使用 java.util.concurrent 包中的专用类。
代码示例:
public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } } // 在单独对象上的部分代码同步: private final Object lock = new Object(); public void complexIncrement() { synchronized (lock) { // 临界区 count++; } }
关键特点:
synchronized 方法和 synchronized 块有什么区别?
同步方法会锁定对象(如果方法是静态的,则锁定类的监视器),同步块允许明确指定监视对象,从而提供更大的灵活性。
如果在一个对象中同步不同的方法会发生什么?
如果两个方法都被标记为 synchronized(非静态),它们都将使用该对象(this)作为监视器。在一个线程执行这两个方法时,另一个线程无法进入任一方法。
是否可以同步静态方法和普通方法?它们彼此之间如何解锁?
静态方法使用类本身的监视器(Class 对象),而普通方法使用实例对象。因此,静态 synchronized 方法和普通 synchronized 方法不会相互锁定。
开发者同步不同对象的方法,但在所有地方都使用相同的 String 作为监视器。结果是由于重用池中的字符串,造成了减速和“随机”的死锁。
优点:
缺点:
基于仅在类内创建的私有最终对象进行同步(private final Object lock),并且临界区的时间最小。
优点:
缺点: