java线程:互斥锁与读写锁

两种互斥锁机制:

1、synchronized

2、ReentrantLock

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

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

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

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

例子1:

[java]view plaincopy

    importjava.util.HashMap;importjava.util.Map;importjava.util.concurrent.locks.ReadWriteLock;importjava.util.concurrent.locks.ReentrantReadWriteLock;/***@authoramber2012**读写锁:ReadWriteLock**在多线程的环境下,对同一份数据进行读写,会涉及到线程安全的问题。比如在一个线程读取数据的时候,另外一个线程在*写数据,而导致前后数据的不一致性;一个线程在写数据的时候,另一个线程也在写,同样也会导致线程前后看到的数据的*不一致性。**这时候可以在读写方法中加入互斥锁,任何时候只能允许一个线程的一个读或写操作,而不允许其他线程的读或写操作,这*样是可以解决这样以上的问题,但是效率却大打折扣了。因为在真实的业务场景中,一份数据,读取数据的操作次数通常高*于写入数据的操作,而线程与线程间的读读操作是不涉及到线程安全的问题,没有必要加入互斥锁,只要在读-写,写-写期*间上锁就行了。**对于这种情况,读写锁则最好的解决方案!**读写锁的机制:*"读-读"不互斥*"读-写"互斥*"写-写"互斥**即在任何时候必须保证:*只有一个线程在写入;*线程正在读取的时候,写入操作等待;*线程正在写入的时候,其他线程的写入操作和读取操作都要等待;**以下是一个缓存类:用于演示读写锁的操作:重入、降级*/publicclassCachedData{//缓存都应该是单例的,在这里用单例模式设计:privatestaticCachedDatacachedData=newCachedData();privatefinalReadWriteLocklock=newReentrantReadWriteLock();//读写锁privateMap<String,Object>cache=newHashMap<String,Object>();//缓存privateCachedData(){}publicstaticCachedDatagetInstance(){returncachedData;}//读取缓存:publicObjectread(Stringkey){lock.readLock().lock();Objectobj=null;try{obj=cache.get(key);if(obj==null){lock.readLock().unlock();//在这里的时候,其他的线程有可能获取到锁lock.writeLock().lock();try{if(obj==null){obj="查找数据库";//实际动作是查找数据库//把数据更新到缓存中:cache.put(key,obj);}}finally{//当前线程在获取到写锁的过程中,可以获取到读锁,这叫锁的重入,然后导致了写锁的降级,称为降级锁。//利用重入可以将写锁降级,但只能在当前线程保持的所有写入锁都已经释放后,才允许重入reader使用//它们。所以在重入的过程中,其他的线程不会有获取到锁的机会(这样做的好处)。试想,先释放写锁,在//上读锁,这样做有什么弊端?–如果这样做,那么在释放写锁后,在得到读锁前,有可能被其他线程打断。//重入————>降级锁的步骤:先获取写入锁,然后获取读取锁,最后释放写入锁(重点)lock.readLock().lock();lock.writeLock().unlock();}}}finally{lock.readLock().unlock();}returnobj;}}

例子2:[java]view plaincopy

    importjava.util.Map;importjava.util.TreeMap;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReadWriteLock;importjava.util.concurrent.locks.ReentrantReadWriteLock;importjavax.xml.crypto.Data;/***@authoramber2012**jdk文档中关于ReentrantReadWriteLock类使用的一个很好的例子,以下是具体的介绍:**在使用某些种类的Collection时,可以使用ReentrantReadWriteLock来提高并发性。通常,在预期collection*很大,读取者线程访问它的次数多于写入者线程,并且entail操作的开销高于同步开销时,这很值得一试。例如,以下*是一个使用TreeMap的类,预期它很大,并且能被同时访问。*/publicclassRWDictionary{privatefinalMap<String,Data>map=newTreeMap<String,Data>();privatefinalReadWriteLockrwl=newReentrantReadWriteLock();privatefinalLockreadLock=rwl.readLock();privatefinalLockwriteLock=rwl.writeLock();publicDataget(Stringkey){readLock.lock();try{returnmap.get(key);}finally{readLock.unlock();}}publicString[]allKeys(){readLock.lock();try{return(String[])map.keySet().toArray();}finally{readLock.unlock();}}publicDataput(Stringkey,Datavalue){writeLock.lock();try{returnmap.put(key,value);}finally{writeLock.unlock();}}publicvoidclear(){writeLock.lock();try{map.clear();}finally{writeLock.unlock();}}}

好想从现在开始抱着你,紧紧地抱着你,一直走到上帝面前。

java线程:互斥锁与读写锁

相关文章:

你感兴趣的文章:

标签云: