从JVM的角度来看Java的多线程(4)

Note that a single thread can lock an object several times - the runtime system maintains a count of the number of times that the object was locked by the current thread, and only unlocks the object when the counter reaches zero .

而加锁次数减到0的时候,此时对应的锁记录肯定是第一次加锁的锁记录,也就是“最老的”,因此需要把“最老的”锁记录的指针写到对象的MarkWord里,这样当执行轻量级锁解锁的CAS操作的时候就能够成功解锁了。)

偏向锁优化手段

从上述偏向锁核心实现我们可以看出来,当访问一个对象锁的只有一个线程时,偏向锁确实很快,但是一旦有第二个线程来访问,就可能要膨胀为轻量级锁,膨胀的开销是很大的。

所以我们会有一个想法:如果在要给一个对象加偏向锁的时候,能提前知道这个对象会是由单个线程访问还是多个线程访问就好了。那么怎么知道一个没有被访问过的对象是不是仅会被单线程访问呢?我们知道每个对象都有对应的类,我们可以通过和这个对象同属一个类(data type)的其他对象被访问的情况来推测这个对象将要被访问的情况。

因此我们可以从data type的维度来批量操作这个data type下的所有对象的偏向锁:

当某个data type下的所有对象的偏向锁发生revoke次数到达一定阈值的时候,将触发bulk rebias:对该data type下所有对象,将偏向锁重置为初始状态(即可以让下一个访问的线程获得锁的状态),如果对象正在持有锁(当前在synchronized块中),则对该对象执行revoke操作使膨胀为轻量级锁。

当某个data type下执行的bulk rebias次数达到一定阈值时,会触发bulk revocation,该data type下所有对象的偏向锁被膨胀为轻量级锁,而且未来产生的这个data type的实例对象默认就被禁用了偏向锁。

总结

其实抛开实现的细节,java的多线程很简单:

java多线程主要面临的问题就是线程安全问题 --》

线程安全问题是由线程间的通信造成的,多个线程间不通信就没有线程安全问题--》

java中线程通信只能通过类变量和实例变量,因此解决线程安全问题就是解决对变量的安全访问问题--》

java中解决变量的安全访问采用的是同步的手段,同步是通过锁实现的--》

有三种锁能保证变量只有一个线程访问,偏向锁最快但是只能用于从始至终只有一个线程获得锁,轻量级锁较快但是只能用于线程串行获得锁,重量级锁最慢但是可以用于线程并发获得锁,先用最快的偏向锁,每次假设不成立就升级一个重量。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/bdd7864195536f77ad276fc726b9bc62.html