java线程学习-ReadWriteLock学习

       很多时候有这样一个场景:   一个共享资源,比如说一个文件或者一段文字,读线程可以并发执行,并发得查询读取,但是写线程写入的话,只能一个线程操作,并且互斥读线程。java的ReadWriteLock读写锁就是为这种场景准备的。

      直接上读写锁的代码

package codeTest;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @ClassName: ThreadTest3
 * @Description: TODO 生产者 消费者线程测试
 * @author xuejupo [email protected]
 * @date 2015-10-30 下午4:37:33
 * 
 */
public class ThreadTestLock {
	/**
	 * 读写锁
	 */
	static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(false);
	static Lock r = rwl.readLock();
	static Lock w = rwl.writeLock();
	// 计数器,用于生产线程退出
	private static int pCount = 0;
	// 计数器,用于消费退出
	private static int cCount = 0;
	// 线程锁
//	private static Object key = new Object();

	// 资源库最大值
	private static final int MAX_SIZE = 100;

	// 生产者,消费者共同拥有的资源
	private static List<Object> list = new ArrayList<Object>(MAX_SIZE);

	public static void main(String[] a) {
		long start = System.currentTimeMillis();
		producer p = new ThreadTestLock().new producer(1);
		producer p2 = new ThreadTestLock().new producer(2);
		producer p3 = new ThreadTestLock().new producer(3);
		consumer c1 = new ThreadTestLock().new consumer(1);
		consumer c2 = new ThreadTestLock().new consumer(2);
		consumer c3 = new ThreadTestLock().new consumer(3);
		c1.start();
		c2.start();
		c3.start();
		p.start();
		p2.start();
		p3.start();
		try {
			//等待线程全部完成再开始主线程
			c1.join();
			c2.join();
			c3.join();
			p.join();
			p2.join();
			p3.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		long end = System.currentTimeMillis();
		
		System.out.println("程序一共执行了:"+(end - start)+"毫秒");
	}

	/**
	 * 生产者线程
	 * 
	 * @ClassName: producer
	 * @Description: TODO(这里用一句话描述这个类的作用)
	 * @author xuejupo [email protected]
	 * @date 2015-10-31 上午12:04:48
	 * 
	 */
	class producer extends Thread {
		private int i;

		public producer(int i) {
			this.i = i;
		}

		public void run() {
			while (pCount <= 30) {
//				synchronized (key) {
					try {
						rwl.writeLock().lock();
						pCount++;
						if (list.size() == MAX_SIZE) {
							System.out.println("生产者" + i
									+ "获取权限,但是资源库中资源已满,等待消费者消费;");
							Thread.sleep(1000);
//							key.wait();
						} else {
							list.add(new Object());
							System.out
									.println("生产者" + i
											+ "获取权限,向资源库放资源;资源库中现有资源个数为:"
											+ list.size());
							Thread.sleep(1000);
//							key.notify();
						}
					} catch (Exception e) {
						System.out.println("error---------------------");
					}finally{
						rwl.writeLock().unlock();
					}
				}
//			}
		}

	}

	/**
	 * 消费者线程
	 * 
	 * @ClassName: consumer
	 * @Description: TODO(这里用一句话描述这个类的作用)
	 * @author xuejupo [email protected]
	 * @date 2015-10-31 上午12:05:03
	 * 
	 */
	class consumer extends Thread {
		private int i;

		public consumer(int i) {
			this.i = i;
		}

		public void run() {
			while (cCount <= 30) {
			rwl.readLock().lock();
//				synchronized (key) {
				cCount++;
				System.out.println(cCount);
					if (list.size() == 0) {
						System.out.println("消费者" + i + "获取权限,但是资源库中没有资源,等待生产;");
						try {
							Thread.sleep(1000);
//							key.wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							System.out.println("error---------------------");
						}finally{
							System.out.println("finally");
							rwl.readLock().unlock();
						}
					} else {
						System.out.println("消费者" + i + "获取权限,现在资源库有资源;"
								+ list.size() + "个,消费1个资源");
						list.remove(list.size() - 1);
						try {
							Thread.sleep(1000);
//							key.notify();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							System.out.println("error---------------------");
						}finally{
							rwl.readLock().unlock();
						}
					}
				}
//			}
		}

	}
}

       结果:

1
消费者1获取权限,但是资源库中没有资源,等待生产;
2
消费者2获取权限,但是资源库中没有资源,等待生产;
3
消费者3获取权限,但是资源库中没有资源,等待生产;
finally
finally
finally
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:1
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:2
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:3
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:4
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:5
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:6
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:7
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:8
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:9
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:10
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:11
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:12
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:13
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:14
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:15
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:16
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:17
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:18
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:19
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:20
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:21
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:22
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:23
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:24
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:25
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:26
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:27
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:28
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:29
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:30
生产者1获取权限,向资源库放资源;资源库中现有资源个数为:31
生产者2获取权限,向资源库放资源;资源库中现有资源个数为:32
4
5
消费者1获取权限,现在资源库有资源;32个,消费1个资源
6
消费者3获取权限,现在资源库有资源;31个,消费1个资源
消费者2获取权限,现在资源库有资源;32个,消费1个资源
生产者3获取权限,向资源库放资源;资源库中现有资源个数为:30
7
消费者3获取权限,现在资源库有资源;30个,消费1个资源
9
消费者1获取权限,现在资源库有资源;29个,消费1个资源
8
消费者2获取权限,现在资源库有资源;28个,消费1个资源
10
消费者3获取权限,现在资源库有资源;27个,消费1个资源
11
消费者2获取权限,现在资源库有资源;26个,消费1个资源
10
消费者1获取权限,现在资源库有资源;25个,消费1个资源
12
13
消费者3获取权限,现在资源库有资源;24个,消费1个资源
消费者1获取权限,现在资源库有资源;24个,消费1个资源
14
消费者2获取权限,现在资源库有资源;22个,消费1个资源
15
17
16
消费者1获取权限,现在资源库有资源;21个,消费1个资源
消费者2获取权限,现在资源库有资源;21个,消费1个资源
消费者3获取权限,现在资源库有资源;21个,消费1个资源
19
20
消费者3获取权限,现在资源库有资源;18个,消费1个资源
18
消费者1获取权限,现在资源库有资源;18个,消费1个资源
消费者2获取权限,现在资源库有资源;17个,消费1个资源
21
消费者3获取权限,现在资源库有资源;15个,消费1个资源
23
消费者1获取权限,现在资源库有资源;14个,消费1个资源
22
消费者2获取权限,现在资源库有资源;13个,消费1个资源
24
26
25
消费者2获取权限,现在资源库有资源;12个,消费1个资源
消费者1获取权限,现在资源库有资源;12个,消费1个资源
消费者3获取权限,现在资源库有资源;12个,消费1个资源
27
消费者2获取权限,现在资源库有资源;9个,消费1个资源
28
消费者3获取权限,现在资源库有资源;8个,消费1个资源
29
消费者1获取权限,现在资源库有资源;7个,消费1个资源
30
消费者2获取权限,现在资源库有资源;6个,消费1个资源
31
32
消费者3获取权限,现在资源库有资源;5个,消费1个资源
消费者1获取权限,现在资源库有资源;5个,消费1个资源
程序一共执行了:44009毫秒

       结果分析:

1.  首先,代码里面的读线程,其实是应该互斥的。所以这种读写锁的形式并不适用于所有场景。他最适用的场景是读操作不互斥,比如单纯得读取一段文字信息的操作,而且更适用于写操作较少的操作。在写操作足够少的并行运算里,他可以最大限度得提高性能。如果写操作过多,获取写锁过多,和普通的并行操作就区别不大了。

2.在本代码里面,3个生产者和3个消费者分别运行,生产者获取写锁,消费者获取读锁,和我以前的博客http://709002341.iteye.com/admin/blogs/2253371对比一下。上一篇博客萝莉普通的生产者和消费者共执行了66604毫秒(博客里没有,我自己在本地加语句执行的),虽然写锁和读锁一样多,读写锁也占据明显优势。当写锁越少的情况下,这种优势越明显

猜你喜欢

转载自709002341.iteye.com/blog/2254221
今日推荐