面试题答案
一键面试1. synchronized实现线程同步原理
对象锁原理
- 监视器锁(Monitor):在Java中,每个对象都有一个监视器锁(Monitor)与之关联。当线程执行到
synchronized
修饰的实例方法或者以对象为锁的同步代码块时,线程需要先获取该对象的监视器锁。 - 获取与释放:如果该对象的监视器锁没有被其他线程持有,那么当前线程可以获取到该锁,进入同步代码块或方法执行;当线程执行完同步代码块或方法,或者在代码块中抛出异常时,线程会自动释放该对象的监视器锁,以便其他线程可以竞争获取。
例如,以下代码中this
就是对象锁:
public class SynchronizedExample {
public synchronized void synchronizedMethod() {
// 同步代码逻辑
}
public void synchronizedBlock() {
synchronized (this) {
// 同步代码逻辑
}
}
}
类锁原理
- 类对象的监视器锁:类锁实际上是针对类的Class对象的锁。因为Class对象在JVM中是唯一的,所以类锁也只有一把。当线程执行
synchronized
修饰的静态方法或者以类的Class对象为锁的同步代码块时,线程需要获取该类的Class对象的监视器锁。 - 同样的获取与释放机制:获取和释放机制与对象锁类似。当线程获取到类锁后,才能进入同步代码块或方法执行,执行完毕后释放锁。
例如:
public class SynchronizedClassExample {
public static synchronized void synchronizedStaticMethod() {
// 同步代码逻辑
}
public static void synchronizedStaticBlock() {
synchronized (SynchronizedClassExample.class) {
// 同步代码逻辑
}
}
}
2. 适合使用synchronized关键字的场景
多线程访问共享资源
当多个线程需要访问并修改共享的资源(如共享变量、文件等)时,为了保证数据的一致性和线程安全,可以使用synchronized
关键字。例如,银行账户类中多个线程对账户余额进行操作:
public class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public synchronized void deposit(double amount) {
balance += amount;
}
public synchronized void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
}
}
public double getBalance() {
return balance;
}
}
避免数据竞争
在一些需要保证操作原子性的场景下,如计数器的自增操作。如果不使用同步机制,多个线程同时对计数器进行自增可能会导致结果不准确。
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
控制并发访问频率
在一些场景下,可能需要控制对某些资源的并发访问频率,例如数据库连接池的获取连接操作。通过synchronized
关键字,可以保证同一时间只有一个线程能够获取连接,避免过多线程同时获取连接导致资源耗尽。
public class ConnectionPool {
private int availableConnections;
public ConnectionPool(int initialConnections) {
this.availableConnections = initialConnections;
}
public synchronized Connection getConnection() {
while (availableConnections <= 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
availableConnections--;
// 返回连接对象
return null;
}
public synchronized void releaseConnection(Connection connection) {
availableConnections++;
notify();
}
}