您的位置:首页 > 编程语言 > Java开发

java中锁的深入理解(一)

2017-05-03 20:08 85 查看
JAVA中的锁分为两种,synchronized和Lock。他们都可以实现同步,具体的用法,可以参考我的另一篇文章。

下面深入探讨一下,synchronized和Lock两种锁方式的原理。

首先看一下synchronized。

public class SynchronizedDemo {
public void method() {
synchronized (this) {
System.out.println("Method 1 start");
}
}
}


上面的代码是一个很简单的使用synchronized来实现同步的程序。它使用了对象的内部锁。

下面看一看它的反编译结果



可以看到,反编译的结果中,有了monitorenter和monitorexit两条指令,这两条指令是JVM指令集中的指令。

下面是monitorenter和moniterexit两条指令在JVM规范中的描述:

monitorenter:

Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain
ownership of the monitor associated with objectref, as follows:
• If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is
then the owner of the monitor.
• If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
• If another thread already owns the monitor associated with objectref, the thread blocks until the monitor's entry count is zero, then tries again to
gain ownership.
每一个object都与一个监视器相关联,一个监视器被锁住当且仅当他有一个使用者。执行moniterenter指令的线程尝试去获得与object相关联监视器的所有权,情况如下:

如果与object相关联的监视器的进入统计数为0,那么线程将进入监视器并将它的进入统计数置为1,该线程获得监视器的所有权。

如果线程已经获得了与该object相关联的监视器的所有权,那么它将再次进入,监视器的进入统计数加1。

如果另一个线程已经获得了与object相关联的监视器,那么线程将会被阻塞,直到监视器的进入统计数为0,然后线程将再次尝试获得监视器的所有权。

monitorexit:

The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits
the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.
执行monitorexit的线程必须是与实例关联的监视器的所有者。线程将监视器的进入统计数减1,如果因此进入统计数的值变为0,那么线程将退出该监视器并不再是该监视器的拥有者。其它阻塞的线程被允许再次尝试进入该监视器。

通过这两段描述,我们很容易就可以理解synchronized的实现原理,另外,我们还可以注意到,一个线程是可以多次进入一个object的监视器的。

我们再来看一看同步方法:

public class SynchronizedMethod {
public synchronized void method() {
System.out.println("Hello World!");
}
}
上面是一个简单的同步方法,使用了对象的内部锁。

我们看一看这段程序反编译后结果:



我们看见,反编译后的代码中有ACC_SYNCHRONIZED标识符。JVM就是根据该标识符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成。

总结:

无论学习什么,底层原理都很重要,既要知其然,也要知其所以然。synchronized的用法虽然简单,了解其底层的原理也很重要。目前,synchronize的效率和lock相比,也还是很不错的,如果需求简单的话,更提倡使用synchronized来进行程序设计。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息