synchronized是原子性内置锁,又称监视器锁。编译器会在同步代码块前后加上monitorenter
和monitorexit
字节码,其依赖操作系统底层互斥锁实现。该关键字主要作用是实现原子性操作和解决共享变量的内存可见性问题。
在执行monitorenter指令时会尝试获取对象锁,如果该对象没有被锁定 / 已经获得了锁,则锁计数器+1,其它竞争的线程进入等待队列中。执行monitorexit执行时将锁计数器-1,当计数器值为0时,释放锁,处于等待队列中的线程再次竞争锁。
synchronized时排他锁,当一个线程获得锁之后其他线程必须等待该线程释放锁才能获得锁,且由于Java中线程和操作系统原生线程是一一对应的,线程被阻塞 / 唤醒时会从用户态切换到内核态,这种转换非常消耗性能。
从内存予以上讲,枷锁的过程会清除工作内存中的共享变量,再从主内存读取,释放锁的过程则是将工作内存中的共享变量写回主内存。
详细机制
-
当多个线程进入同步代码块时,首先进入entryList
-
有一个线程获取到monitor锁后,就赋值给当前线程,并且计数器+1
-
如果线程调用wait方法,将释放锁,当前线程置为null,计数器-1,同时进入waitSet等待被唤醒,调用notify或者notifyAll之后又会进入entryList竞争锁
-
如果线程执行完毕,同样释放锁,计数器-1,当前线程置为null