返回

华为一面查漏补缺第十五期:深入剖析volatile和synchronized

后端

Java并发编程中的volatile和synchronized

在多线程编程中,管理共享资源至关重要。Java提供了两种机制来实现这一目标:volatile和synchronized。了解这些机制对于编写健壮且高效的并发应用程序至关重要。

volatile

想象一下一个共享的变量,多个线程可以同时访问它。如果没有volatile,线程无法保证在对该变量进行更改后,其他线程可以看到这些更改。volatile是一个修饰符,它强制将共享变量的所有更改写入主内存,并通知其他线程这些更改。这确保了所有线程都能看到变量的最新值,从而消除了缓存一致性问题。

synchronized

与volatile不同,synchronized是一个锁机制。它允许线程独占访问共享数据结构,防止其他线程同时访问。当一个线程进入synchronized块时,它将获得该块中共享数据的独占锁。其他线程将被阻塞,直到该线程释放锁。这保证了原子性和一致性,因为一次只能有一个线程访问共享数据。

何时使用volatile

  • 当需要在不同线程之间共享一个变量,但不需要对其进行原子性更新时,可以使用volatile。
  • 变量在不同线程中读取的频率远远高于更新的频率。
  • 需要确保对共享变量的更改对所有线程立即可见。

何时使用synchronized

  • 当需要在不同线程之间共享一个变量,并且需要对该变量进行原子性更新时,可以使用synchronized。
  • 多个线程需要同时访问和更新共享变量。
  • 需要确保对共享变量的更改以原子和一致的方式进行。

代码示例

volatile示例:

public class VolatileCounter {
    private volatile int count;

    public void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

在这个示例中,使用volatile修饰符来确保count变量的更改对所有线程立即可见。

synchronized示例:

public class SynchronizedCounter {
    private int count;

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

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

在这个示例中,使用synchronized块来保护count变量的原子性更新。

常见问题解答

  1. volatile保证原子性吗?

    • 不,volatile不保证原子性。它仅确保对共享变量的更改对所有线程立即可见。
  2. synchronized比volatile性能更差吗?

    • 是的,synchronized比volatile开销更大。它需要获取和释放锁,这会增加性能开销。
  3. 在什么情况下volatile是更好的选择?

    • 当需要在不同线程之间共享一个变量,但不需要对其进行原子性更新时。
  4. 在什么情况下synchronized是更好的选择?

    • 当需要在不同线程之间共享一个变量,并且需要对该变量进行原子性更新时。
  5. 我可以使用volatile和synchronized来保护同一共享变量吗?

    • 不,这不是一个好主意。使用volatile和synchronized来保护同一共享变量可能会导致死锁。