目录
①:MonitorEnter指令获取monitor所有权过程
一、如何解决线程并发安全问题
实际上,所有的并发模式在解决线程安全问题时,采用的方案都是序列化访问临界资源。即在同一时刻,只有一个线程访问临界资源,也称同步互斥访问。Java中提供了两种synchronized和Lock,同步器的本质就是加锁。
注:当多线程执行一个方法时,该方法内部的局部变量并不是临界资源,它们在每个线程的私有栈中,因此不具有共享性,不会导致线程安全问题。
二、synchronized原理详解
1、加锁的方式
synchronizd内置锁是一种对象锁,作用粒度是对象,可以用来实现对临界资源的同步互斥访问,是可冲入的。加锁的方式有三种:
①:同步实例方法,锁是当前实例对象;
②:同步类方法,锁是当前类对象;
③:同步代码块,锁是括号里面的对象。
2、synchronized底层原理
synchronized是基于JVM内置锁实现的,通过内部对象monitor(监视器锁)实现,基于进入与退出monitor对象实现方法和代码块同步。监视器锁的实现依赖底层操作系统的Mutex lock(互斥锁)实现,它是一个重量级锁性能较低。在1.5之后的版本经过优化,内置锁的并发性能已经基本与lock持平。
每个同步对象都有自己的Monitor(监视器锁),加锁过程如下图所示
3、Monitor监视器锁
任何一个对象都有y一个Monitor与之关联,当一个Monitor被持有后,它将处于锁定状态。synchronized在JVM里实现的都是基于进入和退出Monitor对象来实现方法同步和代码块同步,也就是可以通过对MonitorEnter和MonitorExit指令来实现。
①:MonitorEnter指令获取monitor所有权过程
a:如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者;
b:如果线程已经占有该monitor,只是重新进入,则进入monitor的进入数加1;
c:如果其他线程已经占用了monitor,则该线程进入阻塞状态,指导monitor的进入数为0,再重新尝试获取monitor的所有权。
②:MonitorExit指令
a:执行monitorexit的线程必须是Objectref所对应的monitor的所有者。指令进行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者,其他被这个monitor阻塞的线程可以尝试去获取这个monitor的所有权;
b:monitorexit指令出现了两次,第一次为同步正常退出释放锁,第二次为发送异步退出释放锁。