在 Java 中,多线程同步是保证多个线程安全访问共享资源的关键。Java 提供了几种机制来实现线程间的同步,保证了操作的原子性以及内存的可见性。以下是使用同步方法实现多线程同步的几种常见方式:
1. 使用 synchronized
关键字同步方法
当一个方法被 synchronized
关键字修饰时,该方法称为同步方法。同一时间内,只有一个线程能够执行同步方法,其他试图访问该方法的线程将被阻塞,直到当前线程执行完该方法。
java复制代码
public class Counter {
private int count = 0;
// 同步方法
public synchronized void increment() {
count++; // 只有一个线程可以执行此代码块
}
public synchronized int getCount() {
return count;
}
}
2. 使用 synchronized
关键字同步代码块
如果只有方法中的某个代码块需要同步,那么可以使用 synchronized
关键字来同步这个代码块。这种方式比同步整个方法更加细粒度,可能导致更好的性能。
java复制代码
public class Counter {
private int count = 0;
// 使用同步代码块
public void increment() {
synchronized (this) { // 'this' 表示当前实例对象的锁
count++;
}
}
}
同步代码块允许开发者指定锁对象,可以是任意对象。使用 this
作为锁是最常见的情况,代表当前实例。如果是静态方法,可以使用 ClassName.class
作为锁。
3. 使用 ReentrantLock
java.util.concurrent.locks.ReentrantLock
是另一种实现线程同步的方式,提供了与 synchronized
关键字类似的同步控制能力,但它提供了更高的灵活性和控制能力。
java复制代码
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
// 使用 ReentrantLock 实现同步
public void increment() {
lock.lock(); // 获取锁
try {
count++;
} finally {
lock.unlock(); // 释放锁
}
}
}
ReentrantLock
提供了一些额外的功能,例如尝试非阻塞地获取锁(tryLock
)、可中断的锁获取、公平锁等。
注意事项
- 死锁:尝试获取多个锁时,如果不同的线程以不同的顺序获取锁,可能会导致死锁。必须小心设计锁的获取和释放顺序。
- 性能:同步可能会降低性能。如果可能,使用细粒度的同步或者利用
java.util.concurrent
包中的高级同步工具。 - 避免同步不必要的代码:只对修改共享状态的代码块进行同步。
通过正确使用同步机制,可以确保 Java 多线程程序的正确性和效率。在设计多线程程序时,仔细考虑哪些部分的代码需要同步,将有助于避免死锁和性能瓶颈。