深入学习Java synchronized
关键字
synchronized
关键字通过确保在同一时间只有一个线程可以执行某个代码块,从而防止多个线程同时访问共享资源时发生数据不一致的问题。
修饰方法
当synchronized
用于修饰实例方法时,表示当前实例对象是同步锁。这意味着同一个实例的其他synchronized
方法在同一时间只能被一个线程访问。
当多个线程访问同一个实例对象的synchronized
方法时,只有一个线程可以执行该方法,其余线程必须等待。
public class SynchronizedExample {
public synchronized void syncMethod() {
System.out.println("Thread " + Thread.currentThread().getName() + " is executing.");
try {
Thread.sleep(1000); // 模拟操作耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + Thread.currentThread().getName() + " finished.");
}
}
修饰静态方法
当synchronized
用于修饰静态方法时,表示当前类对象是同步锁。这意味着同一个类的其他synchronized
静态方法在同一时间只能被一个线程访问。
静态方法同步是针对类对象的同步,即使是不同实例调用,也会同步。
public class SynchronizedStaticExample {
public static synchronized void syncStaticMethod() {
System.out.println("Thread " + Thread.currentThread().getName() + " is executing static method.");
try {
Thread.sleep(1000); // 模拟操作耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + Thread.currentThread().getName() + " finished static method.");
}
}
修饰代码块
synchronized
代码块可以指定任意对象作为同步锁。它提供了更细粒度的控制,可以仅对需要同步的代码进行同步,而不是整个方法。
代码块同步提供了更灵活的控制,可以对特定对象进行同步。
public class SynchronizedBlockExample {
private final Object lock = new Object();
public void syncBlock() {
synchronized (lock) {
System.out.println("Thread " + Thread.currentThread().getName() + " is executing block.");
try {
Thread.sleep(1000); // 模拟操作耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread " + Thread.currentThread().getName() + " finished block.");
}
}
}
注意事项
-
避免过度同步:过度使用
synchronized
会导致线程竞争加剧,从而降低程序性能。应尽量减少同步代码的范围,仅对必要的部分进行同步。 -
死锁:不当的同步使用会导致死锁现象,例如两个线程互相等待对方释放锁。避免死锁的方法包括按顺序获取锁、使用超时机制等。
-
可见性问题:尽管
synchronized
可以确保代码块内的操作是原子的,但并不能解决所有的可见性问题。在某些情况下,可能需要使用volatile
关键字或java.util.concurrent
包中的其他同步机制来确保变量的可见性。
参考链接
- Java Synchronized: https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html