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 plain copy
  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 plain copy
  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. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值