Java 平台会为它创建的每个对象记录一个特殊的标记,这个标记叫监视器(monitor)。synchronized 使用这些监视器(或叫锁)指明,随后的代码可以临时把对象渲染成不一致的状态。synchronized 修饰的代码块或方法会发生一系列事件,详述如下:
(1) 线程需要修改对象时,会临时把对象变成不一致状态;
(2) 线程获取监视器,指明它需要临时互斥存储这个对象;(3) 线程修改对象,修改完毕后对象处于一致的合法状态;
(4) 线程释放监视器。
如果在修改对象的过程中,其他线程尝试获取锁,Java 会阻塞这次尝试,直到拥有锁的线程释放锁为止。
注意,如果程序没有创建共享数据的多个线程,就无需使用 synchronized 语句。如果自始至终只有一个线程访问某个数据结构,就无需使用 synchronized 保护这个结构。
获取监视器不能避免访问对象,只能避免其他线程声称拥有这个锁——这一点至关重要。为了正确编写并发安全的代码,开发者要确保,修改或读取可能处于不一致状态的对象之前,得先获取对象的监视器。
换个角度来说,如果 synchronized 修饰的方法正在处理一个对象,并且把这个对象变成非法状态,那么读取这个对象的另一个方法(没使用 synchronized 修饰)仍能看到这个不一致的状态。