`

ReentrantReadWriteLock小结

 
阅读更多

           最近在看<<Java并发编程实践>>,有这样一个类:ReentrantReadWriteLock。在这里做一个小结:

 

线程获得写锁的前提条件:

 

    其他线程没有获得读锁:注意一定是其他线程!!!!!!!!!!!!!!!

public class ReadWriteLock{
	static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock();
	static Lock readLock=myLock.readLock();
	static Lock writeLock=myLock.writeLock();
	
	static class MyThread extends Thread{
			public void run() {
				readLock.lock();
				//readLock.unlock();
			}
	}
	public static void main(String args[]){
		
		new MyThread().start();
		
		writeLock.lock();    //通过debug,发现程序阻塞在这里了,发生死锁。下面的"here"打印不出来。
		
		System.out.println("here");
	}
}
//运行结果:
//程序进入死锁,writeLock一直等待。
//只要将readLock.unlock()的注释解开,程序就跑通了。
//可见:要想获得写锁,别的线程必须没有获得读锁。

 

 

    其他线程没有获得写锁:

public class ReadWriteLock{
	static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock();
	static Lock readLock=myLock.readLock();
	static Lock writeLock=myLock.writeLock();
	
	static class MyThread extends Thread{
			public void run() {
				writeLock.lock();
				//writeLock.unlock();
			}
	}
	public static void main(String args[]){
		
		new MyThread().start();
		
		writeLock.lock();    //通过debug,发现程序阻塞在这里了,发生死锁。下面的"here"打印不出来。
		
		System.out.println("here");
	}
}
//运行结果:
//效果同上,发生死锁.若解开writeLock.unlock()的注释则程序正常,成功输出here

 

 

线程进入读锁的前提条件:

 

    其他线程没有获得写锁:

 

public class ReadWriteLock{
	static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock();
	static Lock readLock=myLock.readLock();
	static Lock writeLock=myLock.writeLock();
	
	static class MyThread extends Thread{
			public void run() {
				writeLock.lock();
				//writeLock.unlock();
			}
	}
	public static void main(String args[]){
		
		new MyThread().start();
		
		readLock.lock();    //通过debug,发现程序阻塞在这里了,发生死锁。下面的"here"打印不出来。
		
		System.out.println("here");
	}
}
//结果同上,获得读锁的前提是没有别的线程获得写锁

 

 

 

    没有写请求或者有写请求,但调用线程和持有锁的线程是同一个:

这一条完全不明白是什么意思。

 

 *******************************************************************************

      还有一个特性:一个线程可以先获得写锁,再获得读锁,比如这样:

 

public class ReadWriteLock{
	static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock();
	static Lock readLock=myLock.readLock();
	static Lock writeLock=myLock.writeLock();
	public static void main(String args[]){
		writeLock.lock();
		readLock.lock();
		System.out.println("here");
	}
}
//运行结果:程序正常
here
 

 

    但是:一个线程不能先获得读锁再获得写锁,像这样:

 

public class ReadWriteLock{
	static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock();
	static Lock readLock=myLock.readLock();
	static Lock writeLock=myLock.writeLock();
	public static void main(String args[]){
		readLock.lock();
		writeLock.lock();
		
		System.out.println("here");
	}
}
//运行结果:
//程序进入死循环

   

     因为一个线程可以先获得写锁,再获得读锁。所以:可以实现降级锁,即:      从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。像这样:

public class ReadWriteLock{
	static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock();
	static Lock readLock=myLock.readLock();
	static Lock writeLock=myLock.writeLock();
	public static void main(String args[]){
		writeLock.lock();
		readLock.lock();
		writeLock.unlock();
		
		System.out.println("here");
	}
}
//运行结果:
here

 

但是,从读取锁升级到写入锁是不可能的。

 

     最后一点:ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥。这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量。 

下面根据一个网上的例子说明这一点:

public class ReentrantReadWriteLockSample {  
	  
    public static void main(String[] args) {  
        testReadLock();  
//      testWriteLock();  
    }  
      
    public static void testReadLock() {  
       final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport();  
          
        Runnable runnable = new Runnable() {  
            public void run() {  
                support.get("test");  
            }  
        };  
          
        new Thread(runnable).start();  
        new Thread(runnable).start();  
          
        new Thread(new Runnable() {  
            public void run() {  
                support.put("test", "test");  
            }  
        }).start();  
    }  
      
    public static void testWriteLock() {  
       final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport();  
          
        new Thread(new Runnable() {  
            public void run() {  
                support.put("key1", "value1");  
            }  
        }).start();  
          
        new Thread(new Runnable() {  
            public void run() {  
                support.put("key2", "value2");  
            }  
        }).start();  
          
        new Thread(new Runnable() {  
            public void run() {  
                support.get("key1");  
            }  
        }).start();  
    }  
}  
  
class ReadWriteLockSampleSupport {  
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();  
    private final Lock readLock = lock.readLock();  
    private final Lock writeLock = lock.writeLock();  
      
    private volatile  boolean completed= true; 
    private Map<String,String> cache = new HashMap<String,String>(32);  
    public String get(String key) {  
        readLock.lock();  
        System.out.println(Thread.currentThread().getName() + " read.");  
        startTheCountdown();  //等待5s
        try{  
            return cache.get(key);  
        }  
        finally{  
            readLock.unlock();  
        }  
    }  
      
    public String put(String key, String value) {  
        writeLock.lock();  
        System.out.println(Thread.currentThread().getName() + " write.");  
        startTheCountdown();  
        try{  
            return cache.put(key, value);  
        }  
        finally {  
            writeLock.unlock();  
        }  
    }  
      
    /** 
     * A simple countdown,it will stop after about 5s.  
     */  
    public void startTheCountdown() {  
        long currentTime = System.currentTimeMillis();  
        for(;;) { 
            long diff = System.currentTimeMillis() - currentTime;  
            if(diff > 5000) {  
                break;  
            }  
        }  
    }  
} 
// testReadLock();  和 testWriteLock();  分开运行

      ReentrantReadWriteLockSample中的两个静态测试方法则分别测试了ReadLock和WriteLock的排斥性。 testReadLock()中,开启三个线程,前两者试图获取ReadLock而后者去获取WriteLock。执行结果可以看 到:ReadWriteLockSampleSupport的get()方法中的打印结果在前两个线程中几乎同时显示,而put()中的打印结果则要等上 近5s。这就说明了,ReadLock可以多线程持有并且排斥WriteLock的持有线程。testWriteLock()中,也开启三个线程。前两个 是去获取WriteLock,最后一个获取ReadLock。执行的结果是三个打印结果都有近5s的间隔时间,这说明了WriteLock是独占的。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics