博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

多线程学习 读写锁

Posted on 2018-08-18 18:03  南国木棉  阅读(301)  评论(0编辑  收藏  举报

  类ReentranLock具有万川互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务。这样虽然保证了实例变量的线程安全性,

但效率却是非常低下的。所以在jdk中提供了一种读写锁ReentrantReadWriteLock类,使它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁

ReentrantReadWriteLock来提升该方法的代码运行速度。

  读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁;另一个事写操作相关的做,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。

在没有现成Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻,只允许一个Thread进行写入操作

  读读共享:

  Service类:

  

package ReadAndWriteLock;

import java.io.BufferedWriter;
import java.time.LocalDate;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Service {

	private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
	
	public void read(){
		try {
			try {
				lock.readLock().lock();;
				System.out.println("线程 : "+Thread.currentThread().getName()+"  时间: "+System.currentTimeMillis()+"  获得锁");
				Thread.sleep(10000);
			} finally {
				lock.readLock().unlock();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  主方法:

package ReadAndWriteLock;

public class Run {

		public static void main(String[] args) {
			final Service service=new Service();
			
			new Thread(new Runnable() {
				public void run() {
					service.read();
				}
			}).start();
			
			new Thread(new Runnable() {
				public void run() {
					service.read();
				}
			}).start();
		}
	
}

  控制台:

线程 : Thread-0  时间: 1534585340658  获得锁
线程 : Thread-1  时间: 1534585340659  获得锁

  可以发现,两个线程几乎同时进入了lock方法后面的代码,说明在此使用读写锁可以提供程序运行效率,允许多个线程同时制定lock()方法后面的代码。

  写写互斥:

  Service类

public class Service1 {

	private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
	
	public void write() {
		try {
			try {
				lock.writeLock().lock();;
				System.out.println("线程:  "+Thread.currentThread().getName()+" 时间:  "+System.currentTimeMillis()+"  获得锁");
				Thread.sleep(10000);
			} finally {
				lock.writeLock().unlock();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
}

  主线程:

public class Run {

		public static void main(String[] args) {
			final Service1 service1=new Service1();
			
			new Thread(new Runnable() {
				public void run() {
					service1.write();
				}
			}).start();
			
			new Thread(new Runnable() {
				public void run() {
					service1.write();
				}
			}).start();
		}
	
}

  控制台:

线程:  Thread-0 时间:  1534585587952  获得锁
线程:  Thread-1 时间:  1534585597955  获得锁

  使用写锁代码lock.writeLock()的效果就是同意时间只允许一个线程执行lock()方法后面的代码。

   写读互斥:

  service2类

public class Service2 {

	private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();
	
	public void read() {
		try {
			try {
				lock.readLock().lock();
				System.out.println("线程: "+Thread.currentThread().getName()+"  时间: "+System.currentTimeMillis());
				Thread.sleep(10000);
			} finally {
				lock.readLock().unlock();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void write() {
		try {
			try {
				lock.writeLock().lock();
				System.out.println("线程: "+Thread.currentThread().getName()+"  时间: "+System.currentTimeMillis());
				Thread.sleep(10000);
			} finally {
				lock.writeLock().unlock();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

  主线程:

public class Run {

		public static void main(String[] args) {
			final Service2 service2=new Service2();
			
			new Thread(new Runnable() {
				public void run() {
					service2.write();
				}
			}).start();
			
			new Thread(new Runnable() {
				public void run() {
					service2.read();
				}
			}).start();
		}
	
}

  控制台:

线程: Thread-0  时间: 1534586198910
线程: Thread-1  时间: 1534586208910

  从时间上看,写读操作是互斥的。

  读写互斥:

  将主线程中的方法改为如下:

public class Run {

		public static void main(String[] args) throws InterruptedException {
			final Service2 service2=new Service2();
			
			new Thread(new Runnable() {
				public void run() {
					service2.read();
				}
			}).start();
			Thread.sleep(1000);
			new Thread(new Runnable() {
				public void run() {
					service2.write();
				}
			}).start();
		}
	
}

  控制台:

线程: Thread-0  时间: 1534586426809
线程: Thread-1  时间: 1534586436810

  读写操作也是互斥的。

  结论: 读写,写读,写写都是互斥的:而读读是异步的,非互斥的。

 

  每一个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。