什么是synchronized
关键字?
synchronized
关键字是Java中的一种同步机制,用于控制多个线程对共享资源的访问。它可以确保在同一时刻只有一个线程可以执行被synchronized
修饰的代码块,从而防止数据不一致和竞态条件(Race Condition)的发生。
为什么需要synchronized
关键字?
在多线程编程中,多个线程可能会同时访问和修改共享资源(如变量、对象等)。如果不进行适当的同步,会导致数据不一致的问题。例如,一个线程正在修改一个变量的值,而另一个线程同时在读取这个变量的值,这样可能会读取到不正确的数据。
synchronized
的使用方式
synchronized
关键字可以用在方法上,也可以用在代码块上。下面是详细的解释:
1. 同步方法
使用synchronized
关键字修饰的方法称为同步方法。它可以确保同一个对象的同步方法在同一时刻只能由一个线程执行。
实例方法同步:
public synchronized void synchronizedMethod() { // 代码 }
在这种情况下,同一个对象的其他同步方法在同一时刻也不能被其他线程执行。
静态方法同步:
public static synchronized void synchronizedStaticMethod() { // 代码 }
在这种情况下,同一个类的所有对象的静态同步方法在同一时刻也不能被其他线程执行。
2. 同步代码块
有时候,你不需要整个方法都同步,只需要同步其中的一部分代码。此时可以使用synchronized
代码块。
public void someMethod() { synchronized (this) { // 需要同步的代码 } }
在这种情况下,this
是当前对象,表示在同一时刻只有一个线程可以执行这个代码块。
你也可以同步特定的对象:
public void someMethod() { Object lock = new Object(); synchronized (lock) { // 需要同步的代码 } }
synchronized
的工作原理
synchronized
关键字的工作原理是基于对象锁(Monitor)。每个对象都有一个隐含的锁(Monitor),当一个线程进入同步方法或同步代码块时,它会自动获取这个锁。其他线程在同一时刻不能再获取这个锁,只能等待,直到锁被释放。
- 实例方法同步:锁是当前对象的锁(
this
)。 - 静态方法同步:锁是当前类的类对象锁(
ClassName.class
)。 - 同步代码块:锁是括号中指定的对象。
注意事项
- 死锁:使用不当可能会导致死锁问题,例如两个线程互相等待对方释放锁。
- 性能:同步会影响性能,因为它限制了并发执行的能力。
- 粒度:同步的粒度(方法级别或代码块级别)需要谨慎选择,粒度过大可能导致性能下降,粒度过小可能无法有效防止数据不一致。
举个简单的例子
假设你有一个银行账户类,多个线程可能会同时存款和取款。你可以使用synchronized
关键字来确保这些操作的安全性:
public class BankAccount { private int balance; public BankAccount(int initialBalance) { this.balance = initialBalance; } public synchronized void deposit(int amount) { balance += amount; } public synchronized void withdraw(int amount) { balance -= amount; } public synchronized int getBalance() { return balance; } }
在这个例子中,deposit
、withdraw
和getBalance
方法都被synchronized
关键字修饰,确保在同一时刻只有一个线程可以执行这些方法,从而保证了数据的一致性。