`synchronized`关键字的作用及其实现原理,`wait()`、`notify()`和`notifyAll()`方法的用途及调用条件
synchronized
关键字的作用及其实现原理
作用:
synchronized
关键字是Java中用于控制多个线程对共享资源访问的一个关键字。它确保了在同一时刻,只有一个线程可以执行某个方法或代码块(称为临界区或同步块),从而避免了并发操作可能导致的数据不一致和线程安全问题。
实现原理:
-
锁机制:
synchronized
关键字在Java中是通过锁机制实现的。每个Java对象都可以作为锁。当一个线程访问某个对象的synchronized
方法或代码块时,它会先尝试获取该对象的锁。如果该锁已被其他线程持有,则该线程会被阻塞,直到锁被释放。 -
对象锁与类锁:
- 对象锁: 当访问某个对象的
synchronized
实例方法时,实际上是获取了该对象的锁。对于不同的对象实例,锁是独立的。 - 类锁(Class Lock): 如果在
synchronized
方法中使用了类的Class
对象作为锁,那么该锁是对所有该类实例共享的,称为类锁。这种锁常用于静态同步方法。
- 对象锁: 当访问某个对象的
-
JVM层面的支持:
synchronized
的实现依赖于JVM的底层机制,包括监视器锁(Monitor Locks)的概念。当线程进入同步块时,会尝试获取监视器锁,如果锁被其他线程持有,则当前线程会被阻塞,直到锁被释放。
wait()
、notify()
和notifyAll()
方法的用途及调用条件
用途:
这三个方法是Java中用于线程间通信的,它们必须在同步代码块或同步方法中调用,因为它们都依赖于对象锁。
wait()
: 使当前线程等待(即阻塞),直到其他线程调用此对象的notify()
方法或notifyAll()
方法。调用wait()
方法的线程会释放对象锁,进入等待队列。notify()
: 唤醒正在等待对象监视器上的单个线程。如果有多个线程在等待,选择哪个线程唤醒是任意的。notifyAll()
: 唤醒正在等待此对象监视器上的所有线程。
调用条件:
-
必须在同步代码块或同步方法中调用: 因为这些方法依赖于对象锁,所以它们必须在synchronized块中调用,否则将抛出
IllegalMonitorStateException
异常。 -
wait()
和notify()
/notifyAll()
必须成对使用: 通常在等待条件(由共享变量表示)不满足时调用wait()
,在条件改变后,唤醒等待的线程,这些线程会重新检查条件。 -
wait()
会释放锁,notify()
/notifyAll()
不会释放锁: 调用wait()
的线程会释放对象锁,并进入等待状态。而调用notify()
或notifyAll()
的线程在唤醒其他线程后,仍然持有对象锁,直到它退出同步块或同步方法。
通过这些机制,Java实现了线程间的同步和通信,确保了多线程环境下数据的正确性和程序的安全性。