推荐答案
在 Java 中,synchronized 关键字用于实现线程同步,确保多个线程在访问共享资源时不会发生冲突。synchronized 锁的是对象或类,具体取决于它的使用方式:
- 实例方法:锁的是当前实例对象(
this)。 - 静态方法:锁的是当前类的
Class对象。 - 代码块:锁的是指定的对象或类。
本题详细解读
1. 实例方法中的 synchronized
当一个方法被声明为 synchronized 时,锁的是调用该方法的实例对象。例如:
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
}在这个例子中,increment 方法被 synchronized 修饰,因此当一个线程调用 increment 方法时,它会锁定当前 Counter 实例对象(this),其他线程必须等待锁释放后才能访问该方法。
2. 静态方法中的 synchronized
当一个静态方法被声明为 synchronized 时,锁的是当前类的 Class 对象。例如:
public class Counter {
private static int count = 0;
public static synchronized void increment() {
count++;
}
}在这个例子中,increment 方法是一个静态方法,因此锁的是 Counter.class 对象。这意味着所有线程在调用该静态方法时,都会竞争同一个锁。
3. 代码块中的 synchronized
synchronized 还可以用于代码块,锁的是指定的对象或类。例如:
// www.javascriptcn.com code example
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
}在这个例子中,synchronized 代码块锁的是 lock 对象。这种方式可以更灵活地控制锁的范围,避免锁住整个方法或类。
4. 锁的粒度
synchronized 锁的粒度可以是对象级别或类级别。锁的粒度越小,并发性能越高。因此,在实际开发中,应该尽量减小锁的范围,避免不必要的同步。
5. 锁的可重入性
Java 中的 synchronized 锁是可重入的,这意味着同一个线程可以多次获取同一个锁。例如:
// www.javascriptcn.com code example
public class ReentrantExample {
public synchronized void methodA() {
methodB();
}
public synchronized void methodB() {
// do something
}
}在这个例子中,methodA 和 methodB 都是 synchronized 方法,但同一个线程在调用 methodA 时,可以再次进入 methodB,而不会发生死锁。
6. 锁的释放
当一个线程执行完 synchronized 代码块或方法时,会自动释放锁,其他线程可以获取锁并继续执行。
通过以上分析,我们可以清楚地理解 synchronized 锁的是什么,以及如何在不同场景下使用它来实现线程同步。