`

java线程:互斥锁与读写锁

 
阅读更多

 

java线程:互斥锁与读写锁

分类: java_线程 67人阅读 评论(0) 收藏 举报

两种互斥锁机制:

1、synchronized

2、ReentrantLock

ReentrantLock是jdk5的新特性,采用ReentrantLock可以完全替代替换synchronized传统的锁机制,而且采用ReentrantLock的方式更加面向对象,也更加灵活,网上有很多关于对比两者锁方式的文章,这里就不多口舌了,大家baidu、google一下就水落石出了。在本博客中也写关于这两种锁方式实现的经典例子《生产者消费者》。

synchronized方式:《java线程:三种方式实现生产者消费者问题_1》

ReentranLock方式:《java线程:三种方式实现生产者消费者问题_2》

 

关于读写锁,用语言解释不如直接用代码诠释,以下通过两个例子讲述读写锁以及读写锁的使用:

例子1:

[java] view plaincopy
  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3. import java.util.concurrent.locks.ReadWriteLock;  
  4. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  5.   
  6. /** 
  7.  * @author amber2012 
  8.  *  
  9.  * 读写锁:ReadWriteLock 
  10.  *  
  11.  * 在多线程的环境下,对同一份数据进行读写,会涉及到线程安全的问题。比如在一个线程读取数据的时候,另外一个线程在 
  12.  * 写数据,而导致前后数据的不一致性;一个线程在写数据的时候,另一个线程也在写,同样也会导致线程前后看到的数据的 
  13.  * 不一致性。 
  14.  *  
  15.  * 这时候可以在读写方法中加入互斥锁,任何时候只能允许一个线程的一个读或写操作,而不允许其他线程的读或写操作,这 
  16.  * 样是可以解决这样以上的问题,但是效率却大打折扣了。因为在真实的业务场景中,一份数据,读取数据的操作次数通常高 
  17.  * 于写入数据的操作,而线程与线程间的读读操作是不涉及到线程安全的问题,没有必要加入互斥锁,只要在读-写,写-写期 
  18.  * 间上锁就行了。 
  19.  *  
  20.  * 对于这种情况,读写锁则最好的解决方案! 
  21.  *  
  22.  * 读写锁的机制: 
  23.  *      "读-读"不互斥 
  24.  *      "读-写"互斥 
  25.  *      "写-写"互斥 
  26.  *  
  27.  * 即在任何时候必须保证: 
  28.  *      只有一个线程在写入; 
  29.  *      线程正在读取的时候,写入操作等待; 
  30.  *      线程正在写入的时候,其他线程的写入操作和读取操作都要等待; 
  31.  *  
  32.  * 以下是一个缓存类:用于演示读写锁的操作:重入、降级 
  33.  */  
  34. public class CachedData {  
  35.       
  36.     // 缓存都应该是单例的,在这里用单例模式设计:  
  37.     private static CachedData cachedData = new CachedData();  
  38.     private final ReadWriteLock lock = new ReentrantReadWriteLock();//读写锁  
  39.     private Map<String, Object> cache = new HashMap<String, Object>();//缓存  
  40.       
  41.     private CachedData(){  
  42.     }  
  43.       
  44.     public static CachedData getInstance(){  
  45.         return cachedData;  
  46.     }  
  47.       
  48.     // 读取缓存:  
  49.     public Object read(String key) {  
  50.         lock.readLock().lock();  
  51.         Object obj = null;  
  52.         try {  
  53.             obj = cache.get(key);  
  54.             if (obj == null) {  
  55.                 lock.readLock().unlock();  
  56.                 // 在这里的时候,其他的线程有可能获取到锁  
  57.                 lock.writeLock().lock();  
  58.                 try {  
  59.                     if (obj == null) {  
  60.                         obj = "查找数据库"// 实际动作是查找数据库  
  61.                         // 把数据更新到缓存中:  
  62.                         cache.put(key, obj);  
  63.                     }  
  64.                 } finally {  
  65.                     // 当前线程在获取到写锁的过程中,可以获取到读锁,这叫锁的重入,然后导致了写锁的降级,称为降级锁。  
  66.                     // 利用重入可以将写锁降级,但只能在当前线程保持的所有写入锁都已经释放后,才允许重入 reader使用  
  67.                     // 它们。所以在重入的过程中,其他的线程不会有获取到锁的机会(这样做的好处)。试想,先释放写锁,在  
  68.                     // 上读锁,这样做有什么弊端?--如果这样做,那么在释放写锁后,在得到读锁前,有可能被其他线程打断。  
  69.                     // 重入————>降级锁的步骤:先获取写入锁,然后获取读取锁,最后释放写入锁(重点)  
  70.                     lock.readLock().lock();   
  71.                     lock.writeLock().unlock();  
  72.                 }  
  73.             }  
  74.         } finally {  
  75.             lock.readLock().unlock();  
  76.         }  
  77.         return obj;  
  78.     }  
  79. }  

例子2:
[java] view plaincopy
  1. import java.util.Map;  
  2. import java.util.TreeMap;  
  3. import java.util.concurrent.locks.Lock;  
  4. import java.util.concurrent.locks.ReadWriteLock;  
  5. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  6.   
  7. import javax.xml.crypto.Data;  
  8.   
  9. /** 
  10.  * @author amber2012 
  11.  *  
  12.  * jdk文档中关于ReentrantReadWriteLock类使用的一个很好的例子,以下是具体的介绍: 
  13.  *  
  14.  * 在使用某些种类的 Collection 时,可以使用 ReentrantReadWriteLock 来提高并发性。通常,在预期 collection 
  15.  * 很大,读取者线程访问它的次数多于写入者线程,并且 entail 操作的开销高于同步开销时,这很值得一试。例如,以下 
  16.  * 是一个使用 TreeMap 的类,预期它很大,并且能被同时访问。  
  17.  */  
  18. public class RWDictionary {  
  19.   
  20.     private final Map<String, Data> map = new TreeMap<String, Data>();  
  21.     private final ReadWriteLock rwl = new ReentrantReadWriteLock();  
  22.     private final Lock readLock = rwl.readLock();  
  23.     private final Lock writeLock = rwl.writeLock();  
  24.   
  25.     public Data get(String key) {  
  26.         readLock.lock();  
  27.         try {  
  28.             return map.get(key);  
  29.         } finally {  
  30.             readLock.unlock();  
  31.         }  
  32.     }  
  33.   
  34.     public String[] allKeys() {  
  35.         readLock.lock();  
  36.         try {  
  37.             return (String[]) map.keySet().toArray();  
  38.         } finally {  
  39.             readLock.unlock();  
  40.         }  
  41.     }  
  42.   
  43.     public Data put(String key, Data value) {  
  44.         writeLock.lock();  
  45.         try {  
  46.             return map.put(key, value);  
  47.         } finally {  
  48.             writeLock.unlock();  
  49.         }  
  50.     }  
  51.   
  52.     public void clear() {  
  53.         writeLock.lock();  
  54.         try {  
  55.             map.clear();  
  56.         } finally {  
  57.             writeLock.unlock();  
  58.         }  
  59.     }  
  60. }  
分享到:
评论

相关推荐

    秒杀多线程第十六篇 多线程十大经典案例之一 双线程读写队列数据

    在《秒杀多线程系列》的前十五篇中介绍多线程的相关概念,多线程同步互斥问题《秒杀多线程第四篇一个经典的多线程同步问题》及解决多线程同步互斥的常用方法——关键段、事件、互斥量、信号量、读写锁。为了让大家...

    Java多线程编程 线程同步机制.docx

    这种同一时刻只能被一个线程持有的锁被称为排他锁或者互斥锁。这种锁的实现方式代表了锁的基本原理。本文后续还会提到另外一种锁——读写锁,它可以被看作排他锁的一种相对改进。 Java平台中的锁包括内部锁和显式锁...

    个人总结的深入java多线程开发

    看完《think in java》多线程章节,自己写的多线程文档,还结合了其他的相关网络资料。 线程 一. 线程池 1)为什么要使用线程池 2 2)一个具有线程池的工作队列 3 3)使用线程池的风险: 4 4)有效使用线程池的原则 5...

    Java面试技术面知识扩展包第一弹

    4. 多线程:面试官可能会提问关于多线程编程的问题,如线程的生命周期、线程同步和互斥、线程安全等。您还可能会被要求解释Java中的锁机制、线程池、并发工具类等。 5. 异常处理:面试官可能会询问您关于Java异常...

    Java多线程大量调用百度地图的搜索功能,来做课程作业数据准备

    Java多线程大量调用百度地图的搜索功能,来做课程作业数据准备 读取xls 采用了apache.poi,说实话,使用体验上来说肯定没有python的pandas还用, 多线程共享资源 主要共享的就是一个sheet对象和访问列标row_number...

    java jdk实列宝典 光盘源代码

    线程的互斥;线程的协作;线程join;生产者、消费者问题;线程的优先级;列出虚拟机中所有的线程;守护线程Daemon;线程池;一个死锁的例子; 定时器Timer:包括在指定时间执行任务,在指定时间之后执行任务以及在...

    Java JDK实例宝典

    19 线程——BlockingQueue 第17章 Java与XML 17. 1 用DOM处理XML文档 17. 2 用SAX处理XML文档 17. 3 用XSLT转换XML 17. 4 对象与XML的转换 第18章 Java Mail 18. 1 使用SMTP协议发送...

    Linux多线程服务端编程:使用muduo C++网络库

    2.3不要用读写锁和信号量. . . . . . . . . . . . . . . . .. . . . . . . . . . . 43 2.4封装MutexLock、MutexLockGuard、Condition. . . . . . . . . . . . . . 44 2.5线程安全的Singleton 实现.. . . . . . . . ....

    Java 8无人谈及的八大功能

    其中之一是经典的读写锁(ReadWriteLock),它让你把代码分成两部分:需要互斥的写操作和不需要互斥的读操作。  表面上看起来很不错。问题是读写锁有可能是极慢的(多10倍),这已经和它的初衷相悖了。Java8引入了...

    java范例开发大全源代码

     实例147 随机读写Java类文件 221  第3篇 Java面向对象编程  第8章 面向对象(教学视频:72分钟) 226  8.1 类 226  实例148 简单的通讯录类 226  实例149 简单的长度单位转换类 227  实例150 ...

    java范例开发大全

    13.2 多线程的同步与互斥 436 实例232 多线程同步方法的实例 436 实例233 ATM存取一体机(线程同步互斥) 437 实例234 我的钱哪里去了 440 实例235 门锁打不开了(死锁) 444 实例236 门锁终于被打开了(解决死锁) ...

    Java范例开发大全 (源程序)

     实例147 随机读写Java类文件 221  第3篇 Java面向对象编程  第8章 面向对象(教学视频:72分钟) 226  8.1 类 226  实例148 简单的通讯录类 226  实例149 简单的长度单位转换类 227  实例150 卡车和...

    jstack生成的Thread Dump日志.docx

    Moniter 是Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者class的锁,每个对象都有,也仅有一个 Monitor。 从上图可以看出,每个Monitor在某个时刻只能被一个线程拥有,该线程就是 "Active...

    Java范例开发大全(全书源程序)

    13.2 多线程的同步与互斥 436 实例232 多线程同步方法的实例 436 实例233 ATM存取一体机(线程同步互斥) 437 实例234 我的钱哪里去了 440 实例235 门锁打不开了(死锁) 444 实例236 门锁终于被打开了(解决...

    java范例开发大全(pdf&源码)

    13.2 多线程的同步与互斥 436 实例232 多线程同步方法的实例 436 实例233 ATM存取一体机(线程同步互斥) 437 实例234 我的钱哪里去了 440 实例235 门锁打不开了(死锁) 444 实例236 门锁终于被打开了(解决死锁) ...

    java核心知识点整理.pdf

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    JAVA程序设计教程

    思考与练习.....................................................................................................................12 上机实习题..............................................................

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    ICE分布式程序设计中文版

    15.7 读写递归互斥体 335 15.8 定时锁 338 15.9 监控器 341 15.10 线程 350 15.11 可移植的信号处理 357 15.12 总结 358 第 高级 Ice 363 第 16 章 Ice Run Time 详解 365 16.1 引言 365 16.2 通信器 365 16.3 对象...

Global site tag (gtag.js) - Google Analytics