提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
JAVA代码演示读写锁(通俗易懂)
前言
多线程是java的一大核心之一,作为一个java工程师,必须把多线程吃透!
提示:以下是本篇文章正文内容,下面案例可供参考
一、读写锁的基本概念
1)首先读写锁是互斥的,两者不能同时在一个线程的同一个资源内存在(比如一个方法内同时存在读锁和写锁,因为借助对象去调用方法,锁粒度的是对象,加之互斥,所以不能同时存在),不然会发生死锁。
2)一个线程获得了某个资源的读锁,其他线程就不能获得这个资源的写锁(这个资源可以抽象为某个对象好理解一些),但是可以获得读锁,这里的读锁可以抽象为对于读操作来说不加锁。
3)一个线程获得了某个资源的写锁,其他资源就不能获取这个资源的读锁和写锁(防止脏读)
4)举个例子,一个类A,分别有三个方法,B()、C()、D(),其中B()加了写锁,C()加了读锁,D()方法中调用了B()和C()方法,此时必然会发生死锁,因为互斥。
二、代码示例
1.同时调用读锁和写锁
代码如下(示例):
class MyCache{
Map<String,Object> map=new HashMap<>();
ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
public void put(String key,Object V){
try {
//加了写锁的方法
readWriteLock.writeLock().lock();
map.put(key, V);
}catch (Exception e){
System.out.println(e.getStackTrace());
}finally {
readWriteLock.writeLock().unlock();
}
}
public void get(int key,Object V){
try {
readWriteLock.readLock().lock();//加了读锁
System.out.println(Thread.currentThread().getName() + "即将写入");
this.put(String.valueOf(key*3),V);//加了写锁
System.out.println(Thread.currentThread().getName() + "写入完成");
System.out.println(Thread.currentThread().getName()+"即将读");
map.get(key); //加了读锁
System.out.println(Thread.currentThread().getName()+"读完成");
}catch (Exception e){
System.out.println(e.getStackTrace());
}finally {
readWriteLock.readLock().unlock();
}
}
}
main线程:
public class Lock01 {
public static void main(String[] args) {
MyCache myCache=new MyCache();
for (int i=0;i<5;i++) {
int finalI = i;
new Thread(() -> {
myCache.get(finalI,finalI*3);
}).start();
}
}
}
结果:出现死锁导致阻塞
F:\jdk11.06\bin\java.exe "
Thread-0即将写入
Thread-1即将写入
2.读锁可以相互兼容
代码如下(示例):
class MyCache{
Map<String,Object> map=new HashMap<>();
ReadWriteLock readWriteLock=new ReentrantReadWriteLock();
public void put(String key,Object V){
try {
readWriteLock.readLock().lock();
map.put(key, V);
}catch (Exception e){
System.out.println(e.getStackTrace());
}finally {
readWriteLock.readLock().lock();
System.out.println("");
}
}
public void get(int key,Object V){
try {
readWriteLock.readLock().lock();
System.out.println(Thread.currentThread().getName() + "即将写入");
this.put(String.valueOf(key*3),V);//加了读锁
System.out.println(Thread.currentThread().getName() + "写入完成");
System.out.println(Thread.currentThread().getName()+"即将读");
map.get(key); //加了读锁
System.out.println(Thread.currentThread().getName()+"读完成");
}catch (Exception e){
System.out.println(e.getStackTrace());
}finally {
readWriteLock.readLock().unlock();
}
}
}
结果:不发生堵塞,多条线程均可获得读锁
Thread-2即将写入
Thread-4即将写入
Thread-3即将写入
Thread-1即将写入
Thread-0即将写入
Thread-0写入完成
Thread-0即将读
Thread-0读完成
Thread-1写入完成
Thread-1即将读
Thread-1读完成
Thread-3写入完成
Thread-3即将读
Thread-3读完成
Thread-2写入完成
Thread-2即将读
Thread-2读完成
Thread-4写入完成
Thread-4即将读
Thread-4读完成
Process finished with exit code 0
总结
读写锁的概念可以通过mysql辅助理解,当锁的粒度是一张表,如果这张表加了读锁,那所有的线程都可以读,却不能写,当加了写锁,其他线程不能写也不能读,只能等待获得写锁的线程释放锁。