一、

   synchronized和ReentrantLock的对比

到现在,看到多线程中,锁定的方式有2种:synchronized和ReentrantLock。两种锁定方式各有优劣,下面简单对比一下:

1、synchronized是关键字,就和if...else...一样,是语法层面的实现,因此synchronized获取锁以及释放锁都是Java虚拟机帮助用户完成的;ReentrantLock是类层面的实现,因此锁的获取以及锁的释放都需要用户自己去操作。特别再次提醒,ReentrantLock在lock()完了,一定要手动unlock()

2、synchronized简单,简单意味着不灵活,而ReentrantLock的锁机制给用户的使用提供了极大的灵活性。这点在Hashtable和ConcurrentHashMap中体现得淋漓尽致。synchronized一锁就锁整个Hash表,而ConcurrentHashMap则利用ReentrantLock实现了锁分离,锁的知识segment而不是整个Hash表

3、synchronized是不公平锁,而ReentrantLock可以指定锁是公平的还是非公平的

4、synchronized实现等待/通知机制通知的线程是随机的,ReentrantLock实现等待/通知机制可以有选择性地通知

5、和synchronized相比,ReentrantLock提供给用户多种方法用于锁信息的获取,比如可以知道lock是否被当前线程获取、lock被同一个线程调用了几次、lock是否被任意线程获取等等

总结起来,我认为如果只需要锁定简单的方法、简单的代码块,那么考虑使用synchronized,复杂的多线程处理场景下可以考虑使用ReentrantLock。当然这只是建议性地,还是要具体场景具体分析的。

最后,查看了很多资料,JDK1.5版本只有由于对synchronized做了诸多优化,效率上synchronized和ReentrantLock应该是差不多。

二、读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!

  ReentrantReadWriteLock会使用两把锁来解决问题,一个读锁,一个写锁
线程进入读锁的前提条件:
    没有其他线程的写锁,
    没有写请求或者有写请求,但调用线程和持有锁的线程是同一个

线程进入写锁的前提条件:
    没有其他线程的读锁
    没有其他线程的写锁

到ReentrantReadWriteLock,首先要做的是与ReentrantLock划清界限。它和后者都是单独的实现,彼此之间没有继承或实现的关系。然后就是总结这个锁机制的特性了: 
     (a).重入方面其内部的WriteLock可以获取ReadLock,但是反过来ReadLock想要获得WriteLock则永远都不要想。 
 
 
 (b).WriteLock可以降级为ReadLock,顺序是:先获得WriteLock再获得ReadLock,然后释放WriteLock,这时候线程将保持Readlock的持有。反过来ReadLock想要升级为WriteLock则不可能,为什么?参看(a),呵呵. 
     (c).ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥。这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量。 
     (d).不管是ReadLock还是WriteLock都支持Interrupt,语义与ReentrantLock一致。 
     (e).WriteLock支持Condition并且与ReentrantLock语义一致,而ReadLock则不能使用Condition,否则抛出UnsupportedOperationException异常。

示例:读锁,写锁及读写锁的缓存机制:

  /**
* 读写锁实现
* 读写锁的缓存机制
*/
// 缓存的map
private Map<String, Object> map = new HashMap<String, Object>();
// 读写锁对象
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private String data="1"; /**
* 进行读操作
* 可以多个读线程同时进入,写线程不能执行
*/
public String getReadWriteLock(String tt) {
//获取读锁,并加锁
Lock readLock = readWriteLock.readLock();
readLock.lock();
try {
System.out.println("线程名称:"+Thread.currentThread().getName() + " be ready to read data!");
// Thread.sleep((long) (Math.random() * 3000));
Thread.sleep(3000); // this.data =tt;
this.data = mainDao.getData(tt);
System.out.println(Thread.currentThread().getName() + "------->>>>have read data :"+data );
return this.data;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//!!!!!!注意:锁的释放一定要在trycatch的finally中,因为如果前面程序出现异常,锁就不能释放了
//释放读锁
readLock.unlock();
} return null;
} /**
* 进行写操作
* 只能一个写线程进入,读线程不能执行
*/
public void putReadWriteLock(String data){
//获取写锁,并加锁
Lock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
System.out.println("线程名称:"+Thread.currentThread().getName() + " be ready to write data!");
Thread.sleep(3000);
this.data = data;
System.out.println(Thread.currentThread().getName() + " have write data: " + data); } catch (InterruptedException e) {
// e.printStackTrace();
System.out.println("error!!!");
}finally {
//释放写锁
writeLock.unlock();
} } /**
* 设计一个缓存系统
* 读写锁的应用。
* JDK1.5自带的读写锁特性,读与读不互斥,读与写互斥,写与写互斥。
* 为什么要使用读写锁?一句话概括那就是提高系统性能,如何提高呢?
* 试想,对于所有对读的操作是不需要线程互斥的,而如果方法内
* 使用了synchronized关键字同步以达到线程安全,对于所有的线程不管是读还是写的操作都要同步。
* 这时如果有大量的读操作时就会又性能瓶颈。
*
* 所以,当一个方法内有多个线程访问,并且方法内有读和写读操作时,
* 提升性能最好的线程安全办法时采用读写锁的机制对读写互斥、写写互斥。这样对于读读就没有性能问题了
* @author zhurudong
*
*/ public void readWriteMathod(String key){ readWriteLock.readLock().lock();//读锁,只对写的线程互斥
// String key = "tt";
Object value = null;
try {
// 尝试从缓存中获取数据
value = map.get(key);
if (value == null) {
readWriteLock.readLock().unlock();//发现目标值为null,释放掉读锁
readWriteLock.writeLock().lock();//发现目标值为null,需要取值操作,上写锁
try {
value = map.get(key);// 很严谨这一步。再次取目标值
if (value == null) {//很严谨这一步。再次判断目标值,防止写锁释放后,后面获得写锁的线程再次进行取值操作
// 模拟DB操作
value = new Random().nextInt(10000) + "test";
map.put(key, value); System.out.println("db completed!");
}
readWriteLock.readLock().lock();//再次对读进行锁住,以防止写的操作,造成数据错乱
} finally {
/*
* 先加读锁再释放写锁读作用:
* 防止在100行出多个线程获得写锁进行写的操作,所以在写锁还没有释放前要上读锁
*/
readWriteLock.writeLock().unlock();
}
} } finally {
readWriteLock.readLock().unlock();
} }

读写锁与多线程验证代码: https://gitee.com/xdymemory00/AsyncWithLock.git

Java 读写锁的实现的更多相关文章

  1. Java读写锁

    Java读写锁,ReadWriteLock.java接口, RentrantReadWriteLock.java实现.通过读写锁,可以实现读-读线程并发,读-写,写-读线程互斥进行.以前面试遇到一个问 ...

  2. Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析

    Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...

  3. java 读写锁

    http://tutorials.jenkov.com/java-concurrency/read-write-locks.html 翻译 读写锁比LOCK的实现更复杂,想象有一个应用程序能读和写一些 ...

  4. java 读写锁详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt124 在java多线程中,为了提高效率有些共享资源允许同时进行多个读的操作, ...

  5. java读写锁ReadWriteLock

    package com.java.concurrent; import java.util.concurrent.locks.ReadWriteLock; import java.util.concu ...

  6. [图解Java]读写锁ReentrantReadWriteLock

    图解ReentrantReadWriteLock 如果之前使用过读写锁, 那么可以直接看本篇文章. 如果之前未使用过, 那么请配合我的另一篇文章一起看:[源码分析]读写锁ReentrantReadWr ...

  7. java读写锁实现数据同步访问

    锁机制最大的改进之一就是ReadWriteLock接口和它的唯一实现类ReentrantReadWriteLock.这个类有两个锁,一个是读操作锁,另一个是写操作锁.使用读操作锁时可以允许多个线程同时 ...

  8. Java读写锁(ReentrantReadWriteLock)学习

    什么是读写锁 平时,我们常见的synchronized和Reentrantlock基本上都是排他锁,这些锁在同一时刻只允许一个线程进行访问,哪怕是读操作.而读写锁是维护了一对锁(一个读锁和一个写锁), ...

  9. 轻松掌握java读写锁(ReentrantReadWriteLock)的实现原理

    转载:https://blog.csdn.net/yanyan19880509/article/details/52435135 前言 前面介绍了java中排它锁,共享锁的底层实现机制,本篇再进一步, ...

随机推荐

  1. grep 过滤.svn文件

    [grep 过滤.svn文件] 问题: 在repository搜索代码时,常常会搜索到.svn的代码,如果不想搜索.svn目录下的相关代码怎么办?    1.使用管道进行双层“过滤”,其中第二次gre ...

  2. 07-SSH综合案例:前台用户模块:结构创建及注册页面跳转

    现在就不要直接访问一个JSP,要通过一个Action映射过去.我现在点击要去一个注册的页面 这还不是一个真正的注册,只是一个页面的跳转. 1.5.2 用户模块 注册功能: 在index.jsp页面中点 ...

  3. 【poj2411】Mondriaan's Dream 状态压缩dp

    AC传送门:http://vjudge.net/problem/POJ-2411 [题目大意] 有一个W行H列的广场,需要用1*2小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法? [题解] 对于 ...

  4. Unity5.x Reflection Probe反射探针

    http://blog.csdn.net/yupu56/article/details/53487216

  5. 图是否是树 · Graph Valid Tree

    [抄题]: 给出 n 个节点,标号分别从 0 到 n - 1 并且给出一个 无向边的列表 (给出每条边的两个顶点), 写一个函数去判断这张`无向`图是否是一棵树. 给出n = 5 并且 edges = ...

  6. 优化 resolv.conf

    DNS lookup 在把域名解析成 IP 过程中耽误了不少时间,尤其是访问比较复杂的网站的时候,比如某个页面包含多个 url,一次请求需要做多次 DNS 解析,并且从用户浏览器到 DNS serve ...

  7. MFC The Screen Flickers When The Image Zoomed

    问题描述 当初写MFC也是不情愿的. 既然写了,遇到一些问题. 解决也废了一切功夫.所以简单的记录一下. 这个问题,也就是使用MFC显示图像的时候, 放缩图像的过程中, 图像会一闪一闪的. 这个问题的 ...

  8. va泛型

    va泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的 ...

  9. cannot be cast to

    java.lang.ClassCastException: com.service.impl.OrderPlanServiceImpl cannot be cast to com.provider.s ...

  10. 微信小程序 tp5上传图片

    test.wxml页面 <view class="title">请选择要反馈的问题</view> <view> <picker bindc ...