JUC的Lock和build-in的synchronized是如何实现的

JUC的Lock和build-in的synchronized是如何实现的

补充JUC的Lock是如何实现的

通过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++中的
iamge
其中

  • _count:就是标识线程有多少线程占用(0,无,1-有,>1重入)
  • _owner:记录持有锁的线程,不持有的时候变成null
  • _WaitSet:调用wait的时候,线程就是进入这个等待队列里的

资料参考

比较浅显

深度文章,涉及自旋锁等,讲述了Lock和synchronized的实现原理

猜你喜欢

转载自blog.csdn.net/w8y56f/article/details/89554213