多线程中的读写锁

一.序言:

    类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()方法后面的任务,这样做虽然保证了实例变量的线程安全性,单效率却是非常低的.所以在JDK中提供了一种读写锁ReentrantReadWriteLock类,使用它可以加快运行效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReentrantReadLock来提升该方法的代码运行速度。
    读写锁表示也有两个锁,一个是读操作相关的锁,也成为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁之间互斥,写锁与写锁互斥,在没有现成Thread进行写入操作时,进行读取操作的多个Thread都可以获取锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作,即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。

二.读读锁demo演示:

1.创建一个功能类,在类中调用ReentrantReadWriteLock读锁的方法

 /**
 * Created by ${ligh} on 2019/7/9 上午8:48
 */
public class Service {
   private ReentrantReadWriteLock lock =  new ReentrantReadWriteLock();

   public void read(){

       try{
           try{
               lock.readLock().lock();
               System.out.println("获得读锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
               Thread.sleep(10000);
           }finally {
               lock.readLock().unlock();
           }
       }catch (Exception e){
           e.printStackTrace();
       }
   }
}

2.分别创建线程A和线程B进行读操作

线程A:

/**
 * Created by ${ligh} on 2019/7/9 上午8:53
 */
public class ThreadA extends Thread{

    private Service service;

    public ThreadA(Service service){
        super();
        this.service=service;
    }
    @Override
    public void run() {
        service.read();
    }
}

线程B:

/**
 * Created by ${ligh} on 2019/7/9 上午8:54
 */
public class ThreadB extends Thread{

    private Service service;

    public ThreadB(Service service){
        super();
        this.service=service;
    }
    @Override
    public void run() {
        service.read();
    }
}

3.测试读读锁:

/**
 * Created by ${ligh} on 2019/7/9 上午8:48
 */
public class TestReadLock {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("A");
        ThreadB threadB = new ThreadB(service);
        threadB.setName("B");
        threadA.start();
        threadB.start();
    }
}

4.测试结果:
在这里插入图片描述
总结:
    通过打印结果来看,两个线程几乎同时进入lock()方法后面的代码,说明了lock.readLock()读锁可以提高程序运行效率,允许多个线程 同时执行lock()方法后面的代码。

三.写写锁demo演示:

1.创建一个功能类,调用ReentrantReadWriteLock写锁的方法

/**
 * Created by ${ligh} on 2019/7/9 上午9:13
 */
public class Service {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void write(){
        try{
            try{
                lock.writeLock().lock();
                System.err.println("获得写锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
                Thread.sleep(1000);
            }finally {
                lock.writeLock().unlock();
            }
        }catch (Exception  e){
            e.printStackTrace();
        }
    }
}

2.分别创建线程A,B调用写操作:

线程A:

/**
 * Created by ${ligh} on 2019/7/9 上午8:53
 */
public class ThreadA extends Thread{

    private Service service;

    public ThreadA(Service service){
        super();
        this.service=service;
    }
    @Override
    public void run() {
        service.write();
    }
}

线程B:

/**
 * Created by ${ligh} on 2019/7/9 上午8:54
 */
public class ThreadB extends Thread{

    private Service service;

    public ThreadB(Service service){
        super();
        this.service=service;
    }

    @Override
    public void run() {
        service.write();
    }

}

3.创建测试类:

/**
 * Created by ${ligh} on 2019/7/9 上午9:18
 */
public class TestWriteLock {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("A");

        ThreadB threadB = new ThreadB(service);
        threadB.setName("B");

        threadA.start();
        threadB.start();
    }
}

4.测试结果:
在这里插入图片描述
总结:
通过打印结果显示: 使用写锁代码lock.writeLock()的效果就是同一时间只允许一个线程执行lock()后面的代码,也就是互斥了。

四.读写锁demo演示:

1.创建一个功能类,调用ReentrantReadWriteLock读锁和写锁的方法

/**
 * Created by ${ligh} on 2019/7/9 上午9:25
 */
public class Service {

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * 读锁
     */
    public void read(){
        try{
            try{
                lock.readLock().lock();
                System.err.println("获得读锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
                Thread.sleep(10000);
            }finally {
                lock.readLock().unlock();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 写锁
     */
    public void write(){
        try{
            try{
                lock.writeLock().lock();
                System.err.println("获得写锁 "+Thread.currentThread().getName()+" "+System.currentTimeMillis());
                Thread.sleep(10000);
            }finally {
                lock.writeLock().unlock();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

2.创建线程A调用读锁,线程B调用写锁

线程A:

/**
 * Created by ${ligh} on 2019/7/9 上午9:30
 *
 * 线程A调用读锁
 */
public class ThreadA extends Thread{

    private Service service;

    public ThreadA(Service service){
        super();
        this.service=service;
    }

    @Override
    public void run() {
        service.read();
    }
}

线程B:

/**
 * Created by ${ligh} on 2019/7/9 上午9:32
 */
public class ThreadB extends Thread{

    private Service service;

    public ThreadB(Service service){
        super();
        this.service = service;
    }

    @Override
    public void run() {
        service.write();
    }
}

3.创建测试类:

/**
 * Created by ${ligh} on 2019/7/9 上午9:33
 */
public class TestReadWriteLock {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA threadA = new ThreadA(service);
        threadA.setName("A");
        ThreadB threadB = new ThreadB(service);
        threadB.setName("B");
        threadA.start();
        threadB.start(); 
    }
}

4.测试结果:

在这里插入图片描述

4.总结:

    1).通过打印结果显示: “读写"操作是互斥的,而且下一个示例说明"写读"操作也是互斥的,即只要出现"写操作"的过程,就是互斥的,
    2).通过测试"读写”,"写读"和"写写"都是互斥的;而"读读"是异步的,非互斥的
    3).通过测试可以使用Lock对象将synchronized关键字替换掉,而且其具有的独特功能也是synchronized所不具有的,在学习并发时,Lock是synchronized关键字的进阶,掌握Lock有助于学习并发包中源代码的实现原理,在并发包中大量的类使用了Lock接口作为同步的处理方式。

个人心得:
最近一直在研究多线程,并且发现里面的东西实际没有那么难,尤其是研究实现原理之后,看JDK的源码就轻松了很多。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值