当前位置:   article > 正文

多线程中的读写锁_多线程读写锁

多线程读写锁

一.序言:

    类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();
       }
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

线程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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

线程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();
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

线程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();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

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(); 
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4.测试结果:

在这里插入图片描述

4.总结:

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/956080
推荐阅读
相关标签
  

闽ICP备14008679号