面试题答案
一键面试使用 synchronized
关键字确保线程安全实现账户余额加减操作
- 定义账户类:
public class Account {
private double balance;
public Account(double initialBalance) {
this.balance = initialBalance;
}
// 使用synchronized修饰实例方法实现对账户余额的加减操作
public synchronized void deposit(double amount) {
balance += amount;
}
public synchronized void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
}
}
public double getBalance() {
return balance;
}
}
- 解释:
- 当多个线程调用
deposit
或withdraw
方法时,由于这些方法被synchronized
修饰,同一时刻只有一个线程能够进入这些方法执行操作。 - 这就确保了对
balance
这个共享资源的操作是线程安全的,避免了多个线程同时修改balance
导致数据不一致的问题。
- 当多个线程调用
synchronized
修饰静态方法和实例方法在并发控制上的不同
synchronized
修饰实例方法:- 锁对象:锁的是当前类的实例对象
this
。 - 并发控制:多个线程访问同一个实例对象的
synchronized
实例方法时,会竞争同一个锁,同一时刻只有一个线程能执行该实例方法。但是,如果多个线程访问不同实例对象的synchronized
实例方法,由于锁对象不同(每个实例对象都有自己的锁),它们不会互相竞争锁,可以并发执行。 - 示例:
- 锁对象:锁的是当前类的实例对象
public class SynchronizedInstanceMethodExample {
public synchronized void instanceMethod() {
// 方法体
}
}
假设有两个 SynchronizedInstanceMethodExample
的实例 obj1
和 obj2
,线程 thread1
调用 obj1.instanceMethod()
,线程 thread2
调用 obj2.instanceMethod()
,这两个线程可以同时执行,因为它们锁的是不同的实例对象。
synchronized
修饰静态方法:- 锁对象:锁的是当前类的
Class
对象(因为静态方法属于类,不属于某个实例)。 - 并发控制:无论有多少个实例对象,只要是调用该类的
synchronized
静态方法,所有线程都会竞争同一个Class
对象的锁。也就是说,同一时刻只有一个线程能执行该类的任何synchronized
静态方法。 - 示例:
- 锁对象:锁的是当前类的
public class SynchronizedStaticMethodExample {
public static synchronized void staticMethod() {
// 方法体
}
}
假设有两个 SynchronizedStaticMethodExample
的实例 obj1
和 obj2
,线程 thread1
通过 obj1.staticMethod()
调用静态方法,线程 thread2
通过 obj2.staticMethod()
调用静态方法,这两个线程不能同时执行,因为它们竞争的是同一个 SynchronizedStaticMethodExample.class
锁。