Java多线程之读写锁 ReentrantReadWriteLock

Java多线程之读写锁 ReentrantReadWriteLock

当我们在执行多线程的时候会加上一个***synchronized***让线程安全。比如代码如下:

public class Main {
	public static void main(String[] args) {
		Runnable r=new Runnable() {
			public synchronized void run() {
				for (int i = 0; i < 3; i++) {
					try {
						Thread.sleep(20);
						System.out.println(Thread.currentThread().getName()+ ":正在进行读操作……");
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName() + ":读操作完毕!");				
			}
		};
		new Thread(r).start();
		new Thread(r).start();
	}
}

从上面代码可以看出在加了synchronized关键字之后,读与读之间,也是互斥的,也就是说,必须等待Thread-0读完之后,才会轮到Thread-1线程读,而无法做到同时读文件,这种情况在大量线程同时都需要读文件的时候,读写锁的效率,明显要高于synchronized关键字的实现。而读写锁可以同时执行读操作,但是只能一个线程执行写的操作。读锁和写锁之间是互斥的,读锁和写锁联合在一起用才能起作用, 如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。
代码实现如下:

package com.hzl.java.Thread;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Main11 {
	private static String[] box = new String[1];
	private static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

	public static void main(String[] args) {
		Runnable r = new Runnable() {
			public void run() {
				System.out.println(Thread.currentThread().getName() + "  准备载入读锁");
				rwl.readLock().lock();
				System.out.println(Thread.currentThread().getName() + "  读锁加载完毕");
				if (box[0] == null) {
					System.out.println(Thread.currentThread().getName() + "  准备卸载读锁");
					rwl.readLock().unlock();
					System.out.println(Thread.currentThread().getName() + "  读锁卸载完毕");
					System.out.println(Thread.currentThread().getName() + "  准备载入写锁");
					rwl.writeLock().lock();
					System.out.println(Thread.currentThread().getName() + "  写锁载入完毕");
					if (box[0] == null) { // 防止后边线程加载数据,使用双端检测机制
						box[0] = String.valueOf(Math.random());
					}
					rwl.writeLock().unlock();
					System.out.println(Thread.currentThread().getName() + "  写锁卸载完毕");
					rwl.readLock().lock();
					System.out.println(Thread.currentThread().getName() + "  读锁卸载完毕");
				} else {
					System.out.println(Thread.currentThread().getName() + box[0]);
				}
				rwl.readLock().unlock();
				System.out.println(Thread.currentThread().getName() + "  写锁载入完毕");
			}
		};
		new Thread(r).start();
		new Thread(r).start();
		new Thread(r).start();
	}
}

执行结果如下:有三种情况
Java多线程之读写锁 ReentrantReadWriteLock_第1张图片
结果分析:当三个线程开始执行时,一开始三个线程同时进到“准备载入读锁”,线程0抢先执行到“卸载读锁完毕”,“准备载入写锁”,让出读锁,线程1抢到读锁,执行到“卸载读锁”,线程2抢到读锁,执行到读锁卸载完毕时,线程2又抢到写锁,此时box[0] ==null,所以给box[0]赋值,执行完毕后,让出写锁,此时线程0抢到写锁,box[0] != null,所以不赋值,线程执行完毕,让出写锁,线程1抢到写锁,box[0] != null,所以不赋值执行完毕之后,线程1抢到读锁,然后释放读锁,线程2抢到读锁,释放读锁,线程0抢到读锁,释放读锁。
Java多线程之读写锁 ReentrantReadWriteLock_第2张图片
结果分析:线程开始执行时,线程2和线程0开始准备载入读锁,线程2抢到读锁,当线程2执行到完毕,让出读锁,线程1开始准备载入读锁,线程2又抢到写锁,此时box[0]==null,所以给box[0] 赋值。执行完毕后,让出写锁,此时线程1抢到读锁,此时的box[0] !=null,所以直接输出box[0]的值,让出读锁,此时线程0抢到读锁,情况和线程1相同,所以让出读锁,此时线程2在执行到“写锁卸载完毕”后抢到读锁,然后又释放读锁。
Java多线程之读写锁 ReentrantReadWriteLock_第3张图片
结果分析:线程开始时,线程0 和线程1进入准备载入读锁,此时线程0先抢到线程执行权,先拿到读锁,此时线程1又抢到线程执行权,拿到读锁,执行完毕后,释放读锁,此时线程2开始执行,准备载入读锁,线程1抢到写锁,此时box[0] ==null,所以给box[0]赋值,执行完毕卸载写锁,然后又拿到读锁,释放读锁。此时线程2拿到读锁,此时box[0] !=null ,所以直接输出box[0]的值。让出读锁,线程执行完。此时线程0在拿到写锁,此时的box[0]!=null,所以不赋值,释放写锁,在拿到读锁,卸载读锁。

你可能感兴趣的:(java多线程,java多线程之读写锁)