目录
- 一、读写锁的理解
- 二、读写锁的代码示例
- 三、多个线程进行读操作的测试案例
- 四、多个线程进行写操作的测试案例
- 五、多个线程进行读写操作的测试案例
一、读写锁的理解
- 读写锁实际维护了一对锁,一个读锁,一个写锁,通过分离读锁和写锁,使得其并发性比独占式锁(排他锁)有了很大的提升。
- 读锁(共享锁):同一时刻可以允许多个线程访问共享资源。
- 写锁(排他锁):在写线程访问的时候,所有的读线程和其他写线程都会被阻塞。即如果一个线程想要去写共享资源,就不应该再有其他线程可以对该共享资源进行读或者是写操作了。
二、读写锁的代码示例
package com.xz.thread.t11;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @description: 读写锁代码示例
* @author: xz
*/
public class Demo {
//声明一个map,存储数据
private Map<String,Object> map =new HashMap<>();
/**
* 1、ReentrantReadWriteLock实例实现了ReadWriteLock接口
* 2、声明一个ReentrantReadWriteLock实例,指向父类ReadWriteLock的引用
* 因为ReentrantReadWriteLock可以保证公平或者非公平
* 3、ReadWriteLock类中只有readLock()和writeLock() 两个方法
*/
private ReadWriteLock rwl =new ReentrantReadWriteLock();
//读锁
private Lock r =rwl.readLock();
//写锁
private Lock w =rwl.writeLock();
//读操作,即获取数据方法
public Object get(String key){
r.lock();//获取读锁
System.out.println(Thread.currentThread().getName()+"【读】操作正在执行--------");
try {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return map.get(key);
}finally {
r.unlock();//释放读锁
System.out.println(Thread.currentThread().getName()+"【读】操作执行完毕!!!!!");
}
}
//写操作,即添加或修改数据方法
public void put(String key,String value){
w.lock();//获取写锁
System.out.println(Thread.currentThread().getName()+"【写】操作正在执行========");
try {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key,value);
}finally {
w.unlock();//释放写锁
System.out.println(Thread.currentThread().getName()+"【写】操作执行完毕!!!!!");
}
}
}
三、多个线程进行读操作的测试案例
1、代码
package com.xz.thread.t11;
/**
* @description: 多个线程进行读操作的测试类
* @author: xz
*/
public class ReadTest {
public static void main(String[] args) {
Demo d =new Demo();
d.put("name","张三");
//第一个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(d.get("name"));
}
}).start();
//第二个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(d.get("name"));
}
}).start();
//第三个线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(d.get("name"));
}
}).start();
}
}
2、输出结果
3、结论
- 多个线程同时读一个资源类是没有任何问题的,所以为了满足在并发的情况下,读取共享资源是可以同时进行的。
四、多个线程进行写操作的测试案例
1、代码
package com.xz.thread.t11;
/**
* @description: 多个线程进行写操作的测试类
* @author: xz
*/
public class WriteTest {
public static void main(String[] args) {
Demo d =new Demo();
//第一个线程
new Thread(new Runnable() {
@Override
public void run() {
d.put("name","张三");
}
}).start();
//第二个线程
new Thread(new Runnable() {
@Override
public void run() {
d.put("name","李四");
}
}).start();
//第三个线程
new Thread(new Runnable() {
@Override
public void run() {
d.put("name","王五");
}
}).start();
}
}
2、输出结果
3、结论
- 如果一个线程想要去写共享资源,就不应该再有其他线程可以对该共享资源进行读或者是写操作了。
五、多个线程进行读写操作的测试案例
1、代码
package com.xz.thread.t11;
/**
* @description: 多个线程进行写操作和读操作的测试类
* @author: xz
*/
public class WriteReadTest {
public static void main(String[] args) {
Demo d =new Demo();
//第一个线程
new Thread(new Runnable() {
@Override
public void run() {
d.put("name","张三");
}
}).start();
//第二个线程
new Thread(new Runnable() {
@Override
public void run() {
d.get("张三");
}
}).start();
}
}
2、输出结果
3、结论
- 在写线程访问的时候,所有的读线程和其他写线程都会被阻塞。