互斥锁与synchronized关键字

互斥锁与synchronized关键字
Acting多线程环境下,确保数据一致性是一个至关重要的问题。其中一个常见的挑战是防止多个线程同时对共享资源进行修改,这可能导致数据竞争、不一致或崩溃。为了应对这一问题,Java提供了几种机制来实现互斥锁(Mutual Exclusion),其中最常用的之一就是java.util.concurrent.atomic.Atomic locks和synchronized关键字。
什么是互斥锁?
互斥锁的英文是 mutual exclusion,字面意思是“相互排除”,其核心思想就是在共享资源被修改时,禁止其他线程继续操作。这种机制可以确保只有单个线程在执行某个操作期间才能获得锁,其他线程必须等待直到当前线程释放锁。
互斥锁广泛应用于以下场景:
- 用户注册系统:防止多个用户同时尝试注册相同用户名
- 文件操作:防止多个程序对同一文件进行修改
- 数据库操作:确保数据完整性
Java中的synchronized关键字
Java语言中,synchronized是一个关键字,它用于实现互斥锁。当一个方法被标记为synchronized时,Java会自动在该方法开始
和结束的地方创建并管理一个互斥锁。这样,任何尝试同时调用这个方法的线程都会被阻止,直到当前线程完成该方法的所有操作。
synchronized关键字的工作原理
- 锁获取:当第一个线程调用带有
synchronized关键字的方法时,Java会自动获取锁。 - 执行方法:允许该线程执行所有被锁保护的语句。
- 锁释放:一旦该方法完成执行,当前线程会自动释放锁。
- 等待释放:其他试图调用同一个方法但未被锁保护的线程会被阻塞,直到当前线程释放锁。
使用 synchronized的一个示例
以下是一个简单的用户注册系统的示例:
synchronized (userAccount.intern()) { |
在这个示例中:
- 使用
synchronized关键字,确保只有单个线程可以修改数据库中的用户信息。 - 字符串池:userAccount.intern() 返回字符串池中与 userAccount 内容相同的字符串实例。如果字符串池中不存在该字符串,则将其添加到池中并返回其引用。
- 同步锁:synchronized 关键字用于确保同一时间只有一个线程可以执行被同步的代码块。当多个线程尝试注册同一个用户账户时,它们都会尝试获取同一个锁对象(即 userAccount.intern() 返回的对象),从而保证这些线程不会同时进入同步代码块。
编写一个正确的synchronized示例
编写一个更复杂的例子,比如并发登录检查:
import java.util.concurrent.atomic.AtomicInteger; |
在这个示例中:
checkLogin和logout方法都使用了synchronized关键字来保护对loginCount计数器的访问。- 这样可以防止多个线程同时修改同一个计数器,确保数据的一致性。
注意事项
- 锁获取的时间:在频繁竞争的情况下,过度使用互斥锁可能会导致性能问题。因此,在决定是否需要使用互斥锁时,应该权衡性能和功能需求。
- 条件等待:当没有其他线程需要互斥锁时,可以考虑使用更轻量的条件变量(如
Concurrent Boolean Locks)来代替互斥锁。这可以提高系统的性能。





