java线程:互斥锁与读写锁

两种互斥锁机制:java

一、synchronized数据库

二、ReentrantLock缓存

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

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

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

 

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

例子1:google

import java.util.HashMap;  
import java.util.Map;  
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
/** 
 * @author amber2012 
 *  
 * 读写锁:ReadWriteLock 
 *  
 * 在多线程的环境下,对同一份数据进行读写,会涉及到线程安全的问题。好比在一个线程读取数据的时候,另一个线程在 
 * 写数据,而致使先后数据的不一致性;一个线程在写数据的时候,另外一个线程也在写,一样也会致使线程先后看到的数据的 
 * 不一致性。 
 *  
 * 这时候能够在读写方法中加入互斥锁,任什么时候候只能容许一个线程的一个读或写操做,而不容许其余线程的读或写操做,这 
 * 样是能够解决这样以上的问题,可是效率却大打折扣了。由于在真实的业务场景中,一份数据,读取数据的操做次数一般高 
 * 于写入数据的操做,而线程与线程间的读读操做是不涉及到线程安全的问题,没有必要加入互斥锁,只要在读-写,写-写期 
 * 间上锁就好了。 
 *  
 * 对于这种状况,读写锁则最好的解决方案! 
 *  
 * 读写锁的机制: 
 *      "读-读"不互斥 
 *      "读-写"互斥 
 *      "写-写"互斥 
 *  
 * 即在任什么时候候必须保证: 
 *      只有一个线程在写入; 
 *      线程正在读取的时候,写入操做等待; 
 *      线程正在写入的时候,其余线程的写入操做和读取操做都要等待; 
 *  
 * 如下是一个缓存类:用于演示读写锁的操做:重入、降级 
 */  
public class CachedData {  
    // 缓存都应该是单例的,在这里用单例模式设计:  
    private static CachedData cachedData = new CachedData();  
    private final ReadWriteLock lock = new ReentrantReadWriteLock();//读写锁  
    private Map<String, Object> cache = new HashMap<String, Object>();//缓存  
      
    private CachedData(){  
    }  
      
    public static CachedData getInstance(){  
        return cachedData;  
    }  
      
    // 读取缓存:  
    public Object read(String key) {  
        lock.readLock().lock();  
        Object obj = null;  
        try {  
            obj = cache.get(key);  
            if (obj == null) {  
                lock.readLock().unlock();  
                // 在这里的时候,其余的线程有可能获取到锁  
                lock.writeLock().lock();  
                try {  .net

                    obj = cache.get(key); //这个是必要的!!!!
                    if (obj == null) {  
                        obj = "查找数据库"; // 实际动做是查找数据库  
                        // 把数据更新到缓存中:  
                        cache.put(key, obj);  
                    }  
                } finally {  
                    // 当前线程在获取到写锁的过程当中,能够获取到读锁,这叫锁的重入,而后致使了写锁的降级,称为降级锁。  
                    // 利用重入能够将写锁降级,但只能在当前线程保持的全部写入锁都已经释放后,才容许重入 reader使用  
                    // 它们。因此在重入的过程当中,其余的线程不会有获取到锁的机会(这样作的好处)。试想,先释放写锁,在  
                    // 上读锁,这样作有什么弊端?--若是这样作,那么在释放写锁后,在获得读锁前,有可能被其余线程打断。  
                    // 重入————>降级锁的步骤:先获取写入锁,而后获取读取锁,最后释放写入锁(重点)  
                    lock.readLock().lock();   
                    lock.writeLock().unlock();  
                }  
            }  
        } finally {  
            lock.readLock().unlock();  
        }  
        return obj;  
    }  
}  线程

 

例子2:

import java.util.Map;  
import java.util.TreeMap;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock;  
  
import javax.xml.crypto.Data;  
  
/** 
 * @author amber2012   *    * jdk文档中关于ReentrantReadWriteLock类使用的一个很好的例子,如下是具体的介绍:   *    * 在使用某些种类的 Collection 时,可使用 ReentrantReadWriteLock 来提升并发性。一般,在预期 collection   * 很大,读取者线程访问它的次数多于写入者线程,而且 entail 操做的开销高于同步开销时,这很值得一试。例如,如下   * 是一个使用 TreeMap 的类,预期它很大,而且能被同时访问。    */   public class RWDictionary {          private final Map<String, Data> map = new TreeMap<String, Data>();       private final ReadWriteLock rwl = new ReentrantReadWriteLock();       private final Lock readLock = rwl.readLock();       private final Lock writeLock = rwl.writeLock();          public Data get(String key) {           readLock.lock();           try {               return map.get(key);           } finally {               readLock.unlock();           }       }          public String[] allKeys() {           readLock.lock();           try {               return (String[]) map.keySet().toArray();           } finally {               readLock.unlock();           }       }          public Data put(String key, Data value) {           writeLock.lock();           try {               return map.put(key, value);           } finally {               writeLock.unlock();           }       }          public void clear() {           writeLock.lock();           try {               map.clear();           } finally {               writeLock.unlock();           }       }   }  

相关文章
相关标签/搜索