简述如何让 Java 的线程彼此同步?
参考答案:
在 Java 中,有多种方法可以让线程彼此同步,以确保它们按照预期的顺序执行。以下是一些常用的方法:
- synchronized 关键字:
synchronized
关键字用于确保一次只有一个线程可以执行一个特定的代码块或方法。当线程尝试访问一个由synchronized
保护的代码块或方法时,它必须首先获得一个锁。如果锁已经被另一个线程持有,那么该线程将被阻塞,直到锁被释放。
例如:
public synchronized void myMethod() {
// only one thread can execute this block of code at a time
}
- wait() 和 notify() 方法:
wait()
方法使当前线程等待,直到另一个线程调用同一个对象的notify()
或notifyAll()
方法。notify()
方法唤醒在此对象监视器上等待的单个线程,而notifyAll()
方法唤醒所有在此对象监视器上等待的线程。
例如:
synchronized(this) {
while (someCondition) {
try {
wait();
} catch (InterruptedException e) {
// handle exception
}
}
}
- ReentrantLock:
ReentrantLock
是一个可重入的互斥锁,它实现了Lock
接口。与synchronized
关键字不同,ReentrantLock
提供了更灵活的锁定机制,例如尝试获取锁(tryLock()
)、响应中断的获取锁(lockInterruptibly()
)以及可以条件地获取锁(tryLock(long time, TimeUnit unit)
)。
例如:
Lock lock = new ReentrantLock();
lock.lock();
try {
// only one thread can execute this block of code at a time
} finally {
lock.unlock();
}
- volatile 关键字:
volatile
关键字用于确保多个线程可以正确共享一个变量的值。当一个变量被声明为volatile
时,它会保证所有线程看到这个变量的值是一致的。
例如:
private volatile boolean flag = false;
- Atomic 类:Java 并发包
java.util.concurrent.atomic
提供了一些原子类,如AtomicInteger
、AtomicLong
、AtomicBoolean
等。这些类提供了一种在多线程环境中安全地更新数值的方式,而无需使用锁。
例如:
AtomicInteger atomicInt = new AtomicInteger(0);
atomicInt.incrementAndGet();
- 使用 BlockingQueue、Semaphore、CountDownLatch、CyclicBarrier 等并发工具:Java 并发包提供了许多高级的并发工具,这些工具可以帮助我们更好地同步和控制线程。
例如,使用 CountDownLatch
可以在一组线程完成某项任务后,允许其他线程继续执行:
CountDownLatch latch = new CountDownLatch(3);
// some threads do some work and then count down the latch
latch.countDown();
// other threads wait for the latch to count down to zero
latch.await();
总的来说,Java 提供了多种方式来同步线程,开发者需要根据具体的业务场景和需求来选择合适的同步方式。