通过Lock对象的一个int标记位(名为state),记录此lock占用的线程数。如果为0表示此lock无占用,则不阻塞,如果>0则表示暂用,需要阻塞。
阻塞使用和释放阻塞使用LockSupport的park/unpark来实现,其调用更底层的native方法来实现。
Lock中大量使用了Unsafe类的CAS方法来保证线程安全,CAS就是比较并替换,例如在修改这个state的时候,使用的是CAS方式。传入预期的值,如果修改过程被其他线程改了,则修改失败。
CAS通过一些更加底层的指令来实现,例如汇编指令cmpxchg,这个指令将比较并改变两个动作绑在一起,成为一个原子操作。原子操作就是说不可再分割,这两个动作(比较、改值)要么一起执行,要么一起放弃。
synchronized是如何实现的每个Object对象都可以成为锁,因为每个Object都有一个监视器(monitor),这就是任何Object对象都可以作为锁的原因。
我们通常说Object是锁,更准确可能是Object的监视器才是锁。
monitor里有标记(count),0就表示当前没线程,1表示有,>1表示重入了。
monitor不光维护锁引用数,还有WaitSet等,这就是调用wait后记录哪些线程在该监视器的队列上。
至于怎么线程休眠、唤醒,这是JVM、操作系统和CPU底层的一些技术,例如JVM提供了一些指令,当然JVM的指令最终是操作系统和CPU的指令的一个封装。比如对于synchronized(lock),对其反编译,会看到monitorenter和monitorexit,这就是JVM提供的指令(通常monitorexit有两个,因为另一个是异常是保证释放的),而synchronized方法,会生成一个ACC_SYNCHRONIZED标记,这就让运行到该方法时,判断当前monitor的count是否为0。
monitor的实现是在C++中的 其中
- _count:就是标识线程有多少线程占用(0,无,1-有,>1重入)
- _owner:记录持有锁的线程,不持有的时候变成null
- _WaitSet:调用wait的时候,线程就是进入这个等待队列里的
比较浅显
深度文章,涉及自旋锁等,讲述了Lock和synchronized的实现原理