返回

深入探讨synchronized:悲观锁与乐观锁的博弈

Android

在多线程编程中,对共享资源的访问控制至关重要。synchronized作为Java中控制并发访问的利器,其背后的原理揭示了悲观锁与乐观锁之间的博弈。

临界区与竞态条件:并发中的双刃剑

在多线程环境中,共享资源的访问就像一场争夺战。临界区,即共享资源被多个线程同时访问的代码块,成为争夺的焦点。当线程争相进入临界区时,可能会出现指令交错,导致竞态条件,从而引发不可预知的错误。

悲观锁:保守严防的竞争策略

synchronized代表的悲观锁策略,可谓是谨慎保守的。它认为多个线程不可信,在进入临界区前,必须先获得该资源的锁。如果锁被其他线程持有,当前线程必须阻塞等待,直至锁被释放,才能进入临界区。

这种策略的优点是,它有效避免了竞态条件的发生,确保了临界区内的代码顺序执行。但缺点也显而易见,阻塞机制降低了程序的吞吐量,当锁竞争激烈时,可能会导致线程长时间等待。

乐观锁:以乐观态度应对并发

与悲观锁截然不同,乐观锁对线程持有更乐观的看法。它允许多个线程同时进入临界区,并不会在进入前进行锁的获取。当线程退出临界区时,才会检查数据是否被其他线程修改过。

如果数据未被修改,则更新操作顺利完成;如果数据被修改,则更新操作失败,此时线程需要回滚并重试。这种策略避免了阻塞,提高了并发性,但同时也带来了并发更新失败的风险。

synchronized原理:巧妙融合两种策略

synchronized巧妙地融合了悲观锁和乐观锁的优势。在synchronized块内,对于涉及共享资源读写操作的代码,它将采用悲观锁策略,强制线程在进入临界区前获取锁。而对于不涉及共享资源操作的代码,它将采用乐观锁策略,允许线程并发执行。

举一反三:深入实践

以下代码展示了synchronized的具体应用:

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized int getCount() {
        return count;
    }
}

increment方法中,synchronized锁住了对count的修改操作,确保了每次只能有一个线程修改count。而在getCount方法中,synchronized仅锁住了count的读操作,允许多个线程并发读取count

结语:博弈不止,优化永无止境

悲观锁和乐观锁的博弈仍在继续,没有绝对的优劣之分。选择哪种策略取决于具体的并发场景和性能要求。通过深刻理解其原理,熟练应用synchronized,我们可以有效控制多线程并发,提高程序的可靠性和性能。