阿里计算机专业面试宝典1
1. synchronized
和 Lock
有哪些区别,使用场景,如何有效阅读 synchronized
的源码
-
定义
synchronized
:它是 Java 的内置关键字,用于实现同步机制,保证在同一时刻只有一个线程可以访问被synchronized
修饰的代码块或方法,从而避免多线程并发访问导致的数据不一致问题。Lock
:Lock
是 Java 中的一个接口,它提供了比synchronized
更灵活的锁机制。通过Lock
接口的实现类(如ReentrantLock
),可以手动控制锁的获取和释放。
-
区别
- 语法层面:
synchronized
是 Java 语言层面的关键字,使用起来较为简洁;Lock
是一个接口,需要显式地调用lock()
和unlock()
方法来获取和释放锁。 - 锁的获取和释放:
synchronized
会自动释放锁,当同步代码块执行完毕或者出现异常时;Lock
必须手动调用unlock()
方法释放锁,通常将其放在finally
块中以确保异常情况下也能释放。 - 锁的特性:
synchronized
是非公平锁;Lock
可以实现公平锁和非公平锁,如ReentrantLock
可以通过构造函数指定是否为公平锁。 - 锁的状态:
synchronized
无法判断锁的状态;Lock
可以通过tryLock()
方法尝试获取锁并返回是否成功,还能通过isLocked()
判断锁的状态。
-
使用场景
synchronized
:适用于代码简单、并发度不高的场景,因为其使用方便,由 JVM 自动管理锁的获取和释放。Lock
:适用于复杂的同步场景,如需要实现公平锁、可中断锁、超时锁等功能。
代码示例
java
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// 使用 synchronized 的示例
class SynchronizedExample {
private int count = 0;
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
}
// 使用 Lock 的示例
class LockExample {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public int getCount() {
return count;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
// 使用 synchronized 的测试
SynchronizedExample syncExample = new SynchronizedExample();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
syncExample.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
syncExample.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Synchronized count: " + syncExample.getCount());
// 使用 Lock 的测试
LockExample lockExample = new LockExample();
t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
lockExample.increment();
}
});
t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
lockExample.increment();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Lock count: " + lockExample.getCount());
}
}
2. 如何有效阅读 synchronized
的源码
- 了解 Java 对象头:
synchronized
是基于对象头中的 Mark Word 来实现锁的,先了解 Mark Word 的结构和状态变化。 - 从字节码层面入手:通过
javap -c
命令查看包含synchronized
代码的字节码,了解其底层指令。 - 结合 JVM 源码:可以查看 HotSpot JVM 的源码,重点关注 ObjectMonitor 类,
synchronized
的底层实现与它密切相关。
-
应用
synchronized
:在简单的多线程共享资源场景中广泛应用,如计数器、单例模式的懒汉式实现等。Lock
:在复杂的并发场景中使用,如读写锁场景(ReentrantReadWriteLock
)、需要可中断锁的场景等。
3. JVM 如何实现自动内存管理, Minor GC 与 Full GC 的触发机制
-
定义
- JVM 自动内存管理:JVM 自动管理 Java 程序的内存分配和回收,开发者无需手动分配和释放内存,避免了内存泄漏和悬空指针等问题。
- Minor GC:也称为新生代垃圾回收,主要回收新生代中的垃圾对象。
- Full GC:也称为全局垃圾回收,会回收整个堆内存,包括新生代、老年代和永久代(Java 8 之前)或元空间(Java 8 及以后)。
-
JVM 自动内存管理原理