读者写者问题是指对于多个读者和多个写者来说,多个读者可以同时阅读数据,读者读取数据时,需要排斥写者;但是只能一次只能由一个读者进行写入,读者写入时,其它写者与读者都阻塞。其中写锁就相当于我们平时经常使用的互斥锁,而读锁就相当于共享锁。因此,针对读者-写者问题,如果我们只是单纯的使用互斥锁来实现,的确能做到按序执行,并且不会出现脏读;但是却无法实现多个读者共享数据。因此,本文使用读写锁来实现读者-写者问题。
代码如下:
import java.util.Random;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.*;
public class ReadWrite {
private ArrayList<Object> list = new ArrayList<>();
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
class Writer
{
public void write(Object data)
{
rwl.writeLock().lock();
String name=Thread.currentThread().getName();
System.out.println(name+"准备往集合写入数据");
try {
Thread.sleep((long) (Math.random() * 1000));
}
catch(InterruptedException e)
{
e.printStackTrace();
}
try{
System.out.println("已经往集合写入数据"+data);
list.add(data);
}
finally {
rwl.writeLock().unlock();
}
}
}
class Reader
{
public void read()
{
rwl.readLock().lock();
String name=Thread.currentThread().getName();
System.out.println(name+"准备开始从集合中读取数据");
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
int size=list.size();
if(size==0)
System.out.println(name+"读取的数据为:"+"当前集合没有数据");
else
{
int index=new Random().nextInt(list.size()-1);
System.out.println(name+"读取的数据为:"+list.get(index));
}
}
finally {
rwl.readLock().unlock();
}
}
}
public static void main(String[] args) {
final ReadWrite rw=new ReadWrite();
for(int i=0;i<5;i++)
{
new Thread() {
public void run() {
while(true)
rw.new Reader().read();
}
}.start();
}
for(int i=0;i<5;i++)
{
new Thread() {
public void run() {
while(true)
rw.new Writer().write(new Random().nextInt(10000));
}
}.start();
}
}
}
运行结果如下:
Thread-3准备开始从集合中读取数据
Thread-4准备开始从集合中读取数据
Thread-2准备开始从集合中读取数据
Thread-1准备开始从集合中读取数据
Thread-0准备开始从集合中读取数据
Thread-2读取的数据为:当前集合没有数据
Thread-3读取的数据为:当前集合没有数据
Thread-0读取的数据为:当前集合没有数据
Thread-4读取的数据为:当前集合没有数据
Thread-1读取的数据为:当前集合没有数据
Thread-6准备往集合写入数据
已经往集合写入数据961
Thread-6准备往集合写入数据
已经往集合写入数据8557
Thread-9准备往集合写入数据
已经往集合写入数据7183
Thread-9准备往集合写入数据
已经往集合写入数据7583
Thread-9准备往集合写入数据
已经往集合写入数据3592
Thread-9准备往集合写入数据
已经往集合写入数据1876
Thread-9准备往集合写入数据
已经往集合写入数据8575
Thread-9准备往集合写入数据
已经往集合写入数据4180
Thread-9准备往集合写入数据
已经往集合写入数据6295
Thread-5准备往集合写入数据
已经往集合写入数据445
Thread-5准备往集合写入数据
已经往集合写入数据8145
Thread-5准备往集合写入数据
已经往集合写入数据7018
Thread-5准备往集合写入数据
已经往集合写入数据3686
Thread-5准备往集合写入数据
已经往集合写入数据6211
Thread-5准备往集合写入数据
已经往集合写入数据2656
Thread-5准备往集合写入数据
已经往集合写入数据1199
Thread-5准备往集合写入数据
已经往集合写入数据9115
Thread-7准备往集合写入数据
已经往集合写入数据4744
Thread-7准备往集合写入数据
已经往集合写入数据8641
Thread-7准备往集合写入数据
已经往集合写入数据7098
Thread-7准备往集合写入数据
已经往集合写入数据1085
Thread-8准备往集合写入数据
已经往集合写入数据7298
Thread-8准备往集合写入数据
已经往集合写入数据1332
Thread-8准备往集合写入数据
已经往集合写入数据8835
Thread-8准备往集合写入数据
已经往集合写入数据1164
Thread-8准备往集合写入数据
已经往集合写入数据8271
Thread-2准备开始从集合中读取数据
Thread-0准备开始从集合中读取数据
Thread-1准备开始从集合中读取数据
Thread-3准备开始从集合中读取数据
Thread-4准备开始从集合中读取数据
Thread-3读取的数据为:8145
Thread-1读取的数据为:6295
Thread-0读取的数据为:961
Thread-2读取的数据为:2656
Thread-4读取的数据为:1164
Thread-6准备往集合写入数据
已经往集合写入数据334
Thread-9准备往集合写入数据
已经往集合写入数据1992
Thread-9准备往集合写入数据
已经往集合写入数据6806
Thread-5准备往集合写入数据
已经往集合写入数据8720
Thread-5准备往集合写入数据
已经往集合写入数据7947
Thread-7准备往集合写入数据
已经往集合写入数据125
Thread-7准备往集合写入数据
已经往集合写入数据9528
Thread-7准备往集合写入数据
已经往集合写入数据7961
Thread-7准备往集合写入数据
已经往集合写入数据7166
Thread-7准备往集合写入数据
已经往集合写入数据3139
Thread-8准备往集合写入数据
已经往集合写入数据9355
Thread-3准备开始从集合中读取数据
Thread-1准备开始从集合中读取数据
Thread-0准备开始从集合中读取数据
Thread-4准备开始从集合中读取数据
Thread-2准备开始从集合中读取数据
Thread-0读取的数据为:7583
Thread-1读取的数据为:8720
Thread-4读取的数据为:125
Thread-3读取的数据为:6211
Thread-2读取的数据为:7183
Thread-6准备往集合写入数据
已经往集合写入数据9425
Thread-9准备往集合写入数据
已经往集合写入数据6221
Thread-9准备往集合写入数据
已经往集合写入数据3974
Thread-9准备往集合写入数据
已经往集合写入数据8571
Thread-5准备往集合写入数据
已经往集合写入数据3709
Thread-7准备往集合写入数据
已经往集合写入数据4982
Thread-7准备往集合写入数据
已经往集合写入数据411
Thread-7准备往集合写入数据
已经往集合写入数据2391
Thread-7准备往集合写入数据
已经往集合写入数据2841
Thread-8准备往集合写入数据
已经往集合写入数据1173
Thread-8准备往集合写入数据
已经往集合写入数据1422
Thread-0准备开始从集合中读取数据
Thread-1准备开始从集合中读取数据
Thread-4准备开始从集合中读取数据
Thread-3准备开始从集合中读取数据
Thread-2准备开始从集合中读取数据
Thread-0读取的数据为:3592
Thread-3读取的数据为:8145
Thread-1读取的数据为:1085
Thread-2读取的数据为:1199
Thread-4读取的数据为:411
以上结果可以看出,读与读操作可以共同进行,而写操作只能单独进行。这就是读写锁带来的好处,能够避免脏读现象,又能在读取数据时实现共享。