Quantcast
Channel: 云图畅想-还原数据的价值 » Java基础
Viewing all articles
Browse latest Browse all 9

Java专题(6)-Java的synchronized和Lock

$
0
0

本文出自 云图畅想-还原数据的价值 ,转载时请注明出处及相应链接。

本文永久链接: http://www.maoxiangyi.cn/index.php/archives/216

Java专题(1)-Java概述、Java发展、Java虚拟机

Java专题(2)-Java内存模型

Java专题(3)-Java对象的创建及对象实例化过程

Java专题(4)-Java的类加载机制

Java专题(5)-Java的Volatile关键字

Java专题(6)-Java的synchronized和Lock

 

synchronized

把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性(atomicity)和 可见性(visibility)。

原子性意味着一个线程一次只能执行由一个指定监控对象(lock)保护的代码,从而防止多个线程在更新共享状态时相互冲突。

当synchronized作用在方法上时,锁住的便是对象实例(this);

当synchronized作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久带,因此静态方法锁相当于该类的一个全局锁;

当synchronized作用于某一个对象实例时,锁住的便是对应的代码块

我们知道锁存在Java对象头里。如果对象是数组类型,则虚拟机用3个Word(字宽)存储对象头,如果对象是非数组类型,则用2字宽存储对象头。而在HotSpot JVM实现中,锁有个专门的名字:对象监视器。

JAVA中的监视器实际是一个代码块,这段代码块同一时刻只允许被一个线程执行。线程要想执行这段代码块的唯一方式是获得监视器。

监视器有两种同步方式:互斥与协作。多线程环境下线程之间如果需要共享数据,需要解决互斥访问数据的问题,监视器可以确保监视器上的数据在同一时刻只会有一个线程在访问。什么时候需要协作?比如:一个线程向缓冲区写数据,另一个线程从缓冲区读数据,如果读线程发现缓冲区为空就会等待,当写线程向缓冲区写入数据,就会唤醒读线程,这里读线程和写线程就是一个合作关系。JVM通过Object类的wait方法来使自己等待,在调用wait方法后,该线程会释放它持有的监视器,直到其他线程通知它才有执行的机会。一个线程调用notify方法通知在等待的线程,这个等待的线程并不会马上执行,而是要通知线程释放监视器后,它重新获取监视器才有执行的机会。如果刚好唤醒的这个线程需要的监视器被其他线程抢占,那么这个线程会继续等待。object类中的notifyAll方法可以解决这个问题,它可以唤醒所有等待的线程,总有一个线程执行。

ReentrantLock

在java.util.concurrent.locks包中有很多Lock的实现类,常用的有ReentrantLock、ReadWriteLock(实现类ReentrantReadWriteLock)。

经过观察ReentrantLock把所有Lock接口的操作都委派到一个Sync类上,sync有两个子类,分别为了支持公平锁和非公平锁而定义,默认情况下为非公平锁。

ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

 

总结:

1:Lock 的锁定是通过Java代码实现的,而 synchronized 是在 JVM 层面上实现的。

2:ReentrantLock可以成为公平锁。所谓公平锁就是让等待最长的线程最早获得该锁(获得锁的顺序和申请锁的顺序是一致的);与之对应的synchronized是非公平的、当然ReentrantLock也可以成为非公平锁;只是公平锁的性能相对差一些。

3:synchronized锁是基于对象的,一个线程占有了锁,其他线程不能再进入这个对象的任何synchronized方法。而ReentrantLock基于对象中段的,可以将对象划分成不同的块,使用不同的锁子。

4:synchronized 在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线程死锁。但是 Lock 的话就享受不到 JVM 带来自动的功能,出现异常时必须在 finally 将锁释放掉,否则将会引起死锁。

5:在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。

6:ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。

 

参考资料:

Java多线程总结之由synchronized说开去

深入JVM锁机制1-synchronized

深入JVM锁机制2-Lock

JDK 5.0 中更灵活、更具可伸缩性的锁定机制

Java SE1.6中的Synchronized


Viewing all articles
Browse latest Browse all 9

Latest Images

Trending Articles





Latest Images