对于线程读写,通常如果线程们做的都是读的操作,加同步锁一次只让一个线程进的话,那么其他线程都是要等的,但是这样十分没有效率,因为读是可以共享的操作,如果期间没有线程写操作,读资源是可以同时进入几个线程的。
则总结归纳就是:
- 读-读不互斥,读读之间不阻塞
- 读-写互斥:阻塞
- 写-写互斥:写写阻塞
那么这几条其实非常好记就是只要有写的操作就互斥,不允许同时进行。下面我们来看一段代码,分别定义了读操作方法和写操作方法,读操作方法我用读锁控制,写操作方法我用写操作控制,然后新建几个线程对读写操作看是不是在读里面是同时还几个线程读,写里面是不是只有一个写。
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReadWriteLock;
/**
* 读写锁Demo
*/
public class ReentrantReadWriteLockDemo {
class MyObject {
private Object object;
private ReadWriteLock lock = new java.util.concurrent.locks.ReentrantReadWriteLock();
public void get() throws InterruptedException {
lock.readLock().lock();//上读锁
try {
System.out.println(Thread.currentThread().getName() + "准备读取数据");
Thread.sleep(new Random().nextInt(1000));
System.out.println(Thread.currentThread().getName() + "读数据为:" + this.object);
} finally {
lock.readLock().unlock();
}
}
public void put(Object object) throws InterruptedException {
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "准备写数据");
Thread.sleep(new Random().nextInt(1000));
this.object = object;
System.out.println(Thread.currentThread().getName() + "写数据为" + this.object);
} finally {
lock.writeLock().unlock();
}
}
}
public static void main(String[] args) {
final MyObject myObject = new ReentrantReadWriteLockDemo().new MyObject();
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 3; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 3; j++) {
try {
myObject.put(new Random().nextInt(1000));//写操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
for (int i = 0; i < 3; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 3; j++) {
try {
myObject.get();//多个线程读取操作
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
executorService.shutdown();
}
}
输出结果为:
pool-1-thread-2准备写数据
pool-1-thread-2写数据为919
pool-1-thread-2准备写数据
pool-1-thread-2写数据为4
pool-1-thread-1准备写数据
pool-1-thread-1写数据为665
pool-1-thread-3准备写数据
pool-1-thread-3写数据为258
pool-1-thread-5准备读取数据
pool-1-thread-4准备读取数据
pool-1-thread-6准备读取数据
pool-1-thread-6读数据为:258
pool-1-thread-5读数据为:258
pool-1-thread-4读数据为:258
pool-1-thread-2准备写数据
pool-1-thread-2写数据为109
pool-1-thread-1准备写数据
pool-1-thread-1写数据为158
pool-1-thread-3准备写数据
pool-1-thread-3写数据为889
pool-1-thread-3准备写数据
pool-1-thread-3写数据为692
pool-1-thread-6准备读取数据
pool-1-thread-5准备读取数据
pool-1-thread-4准备读取数据
pool-1-thread-5读数据为:692
pool-1-thread-6读数据为:692
pool-1-thread-4读数据为:692
pool-1-thread-1准备写数据
pool-1-thread-1写数据为196
pool-1-thread-5准备读取数据
pool-1-thread-4准备读取数据
pool-1-thread-6准备读取数据
pool-1-thread-5读数据为:196
pool-1-thread-4读数据为:196
pool-1-thread-6读数据为:196
我们可以看到读操作是好几个不同线程同时进入并且读到了同样的数字,写操作只进入一个线程,且每次读出来的不一样。这个神奇的读写锁非常适合经常性进行读操作的系统,做到读写分离的读写锁真的会成为你的最爱。