synchronized
锁静态方法和普通方法最大的区别在于锁的对象不同:
1. 锁普通方法(实例方法)
锁住的是调用该方法的实例对象。
效果: 对同一个实例对象调用的多个普通
synchronized
方法,会互相阻塞;不同实例对象则不会互相阻塞。
public synchronized void instanceMethod() {
// 锁住的是当前对象(this)
}
等价于:
public void instanceMethod() {
synchronized(this) {
// ...
}
}
2. 锁静态方法
锁住的是该类的 Class 对象(即
ClassName.class
)。效果: 只要是该类的静态
synchronized
方法,不论调用多少个实例(甚至无需实例),都会被同一个锁限制访问。
public static synchronized void staticMethod() {
// 锁住的是当前类的Class对象(ClassName.class)
}
等价于:
public static void staticMethod() {
synchronized(ClassName.class) {
// ...
}
}
3. 总结对比
4. 举个例子说明区别
class Demo {
public synchronized void instanceMethod() {
System.out.println("实例方法 - " + Thread.currentThread().getName());
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
public static synchronized void staticMethod() {
System.out.println("静态方法 - " + Thread.currentThread().getName());
try { Thread.sleep(1000); } catch (InterruptedException e) {}
}
}
如果两个线程调用同一个实例对象的
instanceMethod
,它们会互相等待;如果两个线程分别调用两个不同实例的
instanceMethod
,则它们不会互相影响;如果两个线程调用的是静态方法
staticMethod
,无论用几个实例或不使用实例,都会互相阻塞。
5. 实践中的使用建议
实例方法同步适合对象级别的共享数据操作。
静态方法同步适合类级别共享数据(静态变量等)操作。
实际开发时,应根据锁的粒度和共享资源的类型,来选择合适的锁对象,避免出现性能瓶颈或锁竞争过于严重的情况。