码迷,mamicode.com
首页 > 编程语言 > 详细

【Java】读写锁 ReadWriteLock接口

时间:2016-05-06 16:08:42      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:

和被synchronized修饰的对象同时只能被一个线程访问不同,ReadWriteLock接口提供了更细粒度锁机制。ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持,但是写入锁是独占的。


下面是测试代码:

import org.junit.Test;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {

    @Test
    public void test1() throws InterruptedException {
        Data data = new Data();
        Worker t1 = new Worker(data, true);//读取数据
        Worker t2 = new Worker(data, true);//读取数据
        t1.start();
        t1.join();
        t2.start();
        t2.join();
    }

    @Test
    public void test2() throws InterruptedException {
        Data data = new Data();
        Worker t1 = new Worker(data, true);//读取数据
        Worker t2 = new Worker(data, false);//设置数据
        t1.start();
        t1.join();
        Thread.sleep(1000);
        t2.start();
        t2.join();
    }

    @Test
    public void test3() throws InterruptedException {
        Data data = new Data();
        Worker t1 = new Worker(data, false);//设置数据
        Worker t2 = new Worker(data, true);//读取数据
        t1.start();
        t1.join();
        Thread.sleep(1000);
        t2.start();
        t2.join();
    }

    @Test
    public void test4() throws InterruptedException {
        Data data = new Data();
        Worker t1 = new Worker(data, false);//设置数据
        Worker t2 = new Worker(data, false);//设置数据
        t1.start();
        t1.join();
        Thread.sleep(1000);
        t2.start();
        t2.join();
    }
}

class Data {
    static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    ReadWriteLock lock = new ReentrantReadWriteLock();
    Lock read = lock.readLock();
    Lock write = lock.writeLock();

    public void set() {
        write.lock();
        System.out.println(Thread.currentThread().hashCode() + " set:begin " + sdf.format(new Date()));
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
        } finally {
            System.out.println(Thread.currentThread().hashCode() + " set:end "+ sdf.format(new Date()));
            write.unlock();
        }
    }

    public int get() {
        read.lock();
        System.out.println(Thread.currentThread().hashCode() + " get :begin " + sdf.format(new Date()));
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
        } finally {
            System.out.println(Thread.currentThread().hashCode() + " get :end " + sdf.format(new Date()));
            read.unlock();
        }
        return 1;
    }
}

class Worker extends Thread {
    Data data;
    boolean read;

    public Worker(Data data, boolean read) {
        this.data = data;
        this.read = read;
    }

    public void run() {
        if (read){
            data.get();
        }
        else{
            data.set();
        }
    }
}


Run test1()  输出结果如下:
751872434 get :begin 2016-05-04 14:53:49.612
1431398495 get :begin 2016-05-04 14:53:49.613
751872434 get :end 2016-05-04 14:53:54.613
1431398495 get :end 2016-05-04 14:53:54.613


Process finished with exit code 0
结果分析:两个线程读取数据的时间是有重合部分的,说明读取锁readLock可以有多个线程同时保持,执行读取锁后,数据还可被其他线程读取。

Run test2()  输出结果如下:
2034193582 get :begin 2016-05-04 15:03:41.996
2034193582 get :end 2016-05-04 15:03:47.001
1431398495 set:begin 2016-05-04 15:03:48.005
1431398495 set:end 2016-05-04 15:03:53.007

Process finished with exit code 0
结果分析:写入数据的线程是在读取数据线程执行完毕之后才执行的,说明读取锁readLock对写入锁writeLock是排斥的,读操作的时候不允许其他线程进行写操作。

Run test3()  输出结果如下:

751872434 set:begin 2016-05-04 15:11:11.406
751872434 set:end 2016-05-04 15:11:16.409
1402691771 get :begin 2016-05-04 15:11:17.410
1402691771 get :end 2016-05-04 15:11:22.413

Process finished with exit code 0
结果分析:读取数据的线程是在写入数据线程执行完毕之后才执行的,说明写入锁writeLock对读取锁readLock是排斥的,写操作的时候不允许其他线程进行读操作。


Run test4()  输出结果如下:

926219290 set:begin 2016-05-04 15:14:53.647
926219290 set:end 2016-05-04 15:14:58.650
2112602078 set:begin 2016-05-04 15:14:59.654
2112602078 set:end 2016-05-04 15:15:04.657

Process finished with exit code 0
结果分析:第二个写入数据的线程是在第一个写入数据线程执行完毕之后才执行的,说明写入锁writeLock之间是互斥的,写操作的时候不允许其他线程进行写入操作。


总结:

使用读写锁 ReadWriteLock时,多个读操作是可以并发进行的,但是写操作对数据资源是独占的。


延伸:

在选取读写锁ReadWriteLoc还是同步锁synchronized的抉择中,我们可以通过两个因素来权衡:

1.读取数据的频率相对于写入数据的频率;

2.数据被写入锁定后,等待执行的线程数;

一般地,在需要并发控制的读写操作中,若读取数据频率较高且不是频繁的写入数据的时候,可以考虑使用读写锁以提高并发效率。


  • 参考文章:

1.ReadWriteLock用法

2.jdk-api-doc/ReadWriteLock.html

【Java】读写锁 ReadWriteLock接口

标签:

原文地址:http://blog.csdn.net/u011356856/article/details/51313528

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!