java同步锁(synchronized)机制再总结

来源:互联网 发布:动漫网asp源码 编辑:程序博客网 时间:2024/05/22 03:09

之前在《对java多线程的线程安全性的一些总结》中对java多线程的线程安全机制做了大体上的总结,今天再对线程安全机制中的同步锁(synchronized)机制再做深入点的总结。

Java中同步锁(synchronized)根据使用场景可以分成三类:方法锁,对象锁,类锁

举例子比较直观

方法锁:

public synchronized  void fun1()

    {

       System.out.println("fun1test");

    }

--上面例子就是典型的方法锁,直接在方法名前用synchronized进行修饰

对象锁:

Object obj=new Object();

public void  fun2()

    {

       synchronized(obj){

       System.out.println("fun1test");

       }

    }

--使用synchronized(obj)的形式实现同步机制,每个线程执行到该同步语句块时,先去或取obj的互斥锁,获取到则执行否则等待,前面线程执行完后释放锁

类锁:

public void fun3()

    {

       synchronized(SynchronizedTest.class)

       {

           System.out.println("fun3test");

       }

    }

--使用synchronized(SynchronizedTest.class)的形式实现同步机制,其实这个是比较常见的类锁的形式,如果用synchronized来修饰静态成员方法或者synchronized(静态变量),其实这种也算类锁。看到这里你大概会有点明白synchronized锁的所谓“分类”。

    其实根本没有所谓的方法锁,对象锁,类锁,是的你没听错,synchronized锁本质上不存在什么方法锁,对象锁,类锁的区别,因为它们本质上全是“对象锁”,所谓的方法锁,比如例子一,实际上是synchronized(this),也就是说调用这个成员方法的对象是用它的互斥锁来实现同步互斥机制的。而所谓的类锁,比如例子三,不管它修饰静态方法,还是synchronized(SynchronizedTest.class)的形式,本质上它也是“对象锁”,只是这个对象有点特殊,它是类对象,是的,在java中,存在类对象。这点是学C++的人比较费解的地方,因为在C++中从来没有 听过类对象这个说法,为什么呢?这个跟java和C++的链接机制的差异有关系,C++是静态链接的,所以在程序的内存中不需要保存完整的类定义的信息,而java是动态链接的,为了实现动态链接,java必须在加载.class文件后保存类定义的完整信息,这样类就被虚拟机分配了一份内存用来保存类的信息,而这块内存就是类对象了。

    说到这里就不得不提到一个概念,就是“对象的互斥锁”,这是什么玩意,一开始我以为是所有java类的最顶层的父类Object的一个成员属性,但是去查看Object的源码,发现并没有这个东西,后来发现对象锁是java虚拟机实现的,简单来说就是每个对象在虚拟机中都对应于一个“对象锁”,这个对象锁由虚拟机来维护,至于对象和对象锁之间的映射关系是怎么实现的还不大清楚,有可能是每个对象的内存中保存一分对象锁的指针或者在每个对象创建中虚拟机填充了一个一个互斥锁对象。任何线程要执行对synchronized保护的语句块时,都要获取到synchronized(obj)中对象obj的锁。获取到该对象锁的线程可以多少访问和执行改语句块,每进入一次,虚拟机在该对象锁中加一,每执行完一次虚拟机在该对象锁中减一。当对象锁值为0时,其他线程才能获取锁进去访问。

这点很类似pv元语,是的,其实synchronized保护的语句块在编译时,会在语句块前后分别插入monitorenter和moniterexist指令,非常类似pv元语的格式,这样就能把这些和我们大学时学的pv元语锁机制联系起来了。

至于虚拟机具体是如何实现锁机制的内容还需进一步探索。


--补充

上面关于类对象的说法有点不正确,虽然类的信息保存在方法区中,但是类对象是保存在堆区中的,只是类对象也有一份指向方法区中类信息的指针。

 

0 0
原创粉丝点击