当我们设计到读写操作时,需要实现读与写的互斥,写与写的互斥,但不需要维护读与读的互斥。
但是使用synchronized无法实现排除读与读的互斥,这时候就需要Lock来实现。
访问测试类:
public class ReadWriteLockTest {
public static void main(String[] args) {
Datetest datetest = new Datetest();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
datetest.set(new Random().nextInt(30));
}
},"写线程:"+i+"->").start();
}
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
datetest.get();
}
},"读线程"+i+"->").start();
}
}
}
不使用同步:
public class Datetest {
private int data;
public /*synchronized*/ void set(int s){
System.out.println(Thread.currentThread().getName()+"----准备写入数据:"+s);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = s;
System.out.println(Thread.currentThread().getName()+"----成功写入数据:"+this.data);
}
public /*synchronized*/ void get(){
System.out.println(Thread.currentThread().getName()+"----准备读取数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.data);
System.out.println(Thread.currentThread().getName()+"----成功读取数据");
}
}
结果:
写线程:0->----准备写入数据:6
写线程:1->----准备写入数据:18
写线程:2->----准备写入数据:16
写线程:3->----准备写入数据:2
写线程:4->----准备写入数据:23
读线程0->----准备读取数据
读线程1->----准备读取数据
读线程2->----准备读取数据
读线程3->----准备读取数据
读线程4->----准备读取数据
写线程:2->----成功写入数据:16
写线程:0->----成功写入数据:16
写线程:4->----成功写入数据:23
写线程:1->----成功写入数据:16
写线程:3->----成功写入数据:2
23
23
读线程2->----成功读取数据
23
读线程1->----成功读取数据
读线程0->----成功读取数据
23
23
读线程3->----成功读取数据
读线程4->----成功读取数据
可以看到结果很乱。
使用synchronized:
public class Datetest {
private int data;
public /*synchronized*/ void set(int s){
System.out.println(Thread.currentThread().getName()+"----准备写入数据:"+s);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = s;
System.out.println(Thread.currentThread().getName()+"----成功写入数据:"+this.data);
}
public /*synchronized*/ void get(){
System.out.println(Thread.currentThread().getName()+"----准备读取数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.data);
System.out.println(Thread.currentThread().getName()+"----成功读取数据");
}
}
结果:
写线程:0->----准备写入数据:2
写线程:0->----成功写入数据:2
读线程4->----准备读取数据
2
读线程4->----成功读取数据
读线程3->----准备读取数据
2
读线程3->----成功读取数据
读线程2->----准备读取数据
2
读线程2->----成功读取数据
读线程1->----准备读取数据
2
读线程1->----成功读取数据
读线程0->----准备读取数据
2
读线程0->----成功读取数据
写线程:4->----准备写入数据:17
写线程:4->----成功写入数据:17
写线程:3->----准备写入数据:7
写线程:3->----成功写入数据:7
写线程:2->----准备写入数据:26
写线程:2->----成功写入数据:26
写线程:1->----准备写入数据:7
写线程:1->----成功写入数据:7
可以看到读与读互斥
使用Lock:
public class Datetest {
private int data;
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public void set(int s){
readWriteLock.writeLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"----准备写入数据:"+s);
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.data = s;
System.out.println(Thread.currentThread().getName()+"----成功写入数据:"+this.data);
}finally {
readWriteLock.writeLock().unlock();
}
}
public void get(){
readWriteLock.readLock().lock();
try{
System.out.println(Thread.currentThread().getName()+"----准备读取数据");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.data);
System.out.println(Thread.currentThread().getName()+"----成功读取数据");
}finally {
readWriteLock.readLock().unlock();
}
}
}
结果:
写线程:0->----准备写入数据:1
写线程:0->----成功写入数据:1
写线程:1->----准备写入数据:24
写线程:1->----成功写入数据:24
写线程:2->----准备写入数据:14
写线程:2->----成功写入数据:14
写线程:3->----准备写入数据:23
写线程:3->----成功写入数据:23
写线程:4->----准备写入数据:0
写线程:4->----成功写入数据:0
读线程0->----准备读取数据
读线程1->----准备读取数据
读线程2->----准备读取数据
读线程3->----准备读取数据
读线程4->----准备读取数据
0
0
0
读线程2->----成功读取数据
0
读线程1->----成功读取数据
读线程3->----成功读取数据
读线程0->----成功读取数据
0
读线程4->----成功读取数据
写与写互斥了但是读与读不互斥。