读写锁是什么
如果没有读写锁,那么使用其他类型的锁,线程无论是做读操作还是写操作,都需要去获取锁,也都需要阻塞等待着锁资源的释放。但是如果仅仅是读操作,其实完全是允许多线程同时进行的,因为读操作不涉及数据的修改,也就不会引起线程安全问题,相反的,多个读操作并行执行,反而提高了效率。而因为写操作涉及数据的修改,会引起线程安全问题,所以写操作就要做到与其他操作的互斥,以此来保证线程的安全。读写锁就提供了这样的机制,它允许多个线程读操作,提高了效率,同时还能保证写操作的线程安全。
读写锁的实现思路
其实就是设计两把锁,第一把叫读锁,获取读锁后,只允许查看数据,而不能修改数据。第二把叫写锁,获取写锁后,既能查看数据也能修改数据。读锁可以被多个线程持有,而写锁则只能被一个线程持有。
读写锁的获取规则
读读共享:一个线程获取了读锁后,另一个线程一样能获取读锁
写写互斥:一个线程获取了写锁后,另一个线程就不能再获取这个写锁了
读写互斥:一个线程获取了读锁后,另一个线程就不能获取写锁了
写读互斥:一个线程获取了写锁后,另一个线程就不能获取读锁了
读写锁代码示例
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 读写锁示例
*/
public class ReadWriteLockDemo {
private static final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(false);
//读锁
private static final ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
//写锁
private static final ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
/**
* 读线程任务
*/
static class Read implements Runnable {
@Override
public void run() {
readLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到读锁");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "准备释放读锁");
readLock.unlock();
}
}
}
/**
* 写线程任务
*/
static class Write implements Runnable {
@Override
public void run() {
writeLock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获取到写锁");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println(Thread.currentThread().getName() + "准备释放写锁");
writeLock.unlock();
}
}
}
public static void main(String[] args) {
new Thread(new Read()).start();
new Thread(new Read()).start();
new Thread(new Write()).start();
new Thread(new Write()).start();
new Thread(new Read()).start();
}
}
运行结果如下:
总结
可以从上述的运行结果发现,相同的一把读写锁,读锁和写锁之间做到了读读共享、写写互斥、读写互斥、写读互斥,用最简单的业务做个示例,读多写少的情况下,可以在query方法中使用读锁,在update等方法中使用写锁,这样就实现了读高效率和写安全。
扫描二维码关注公众号,回复:
11144888 查看本文章