8、ReadWriteLock读写锁

引用学习(狂神说)

为什么要使用ReadWriteLock锁呢?

因为它是更加细粒度的操作,可以提升效率

官方文档

1、有两个锁,读锁和写锁

2、可以做到:读可以有多个线程同时操作,写只能有一个线程操作

3、在频繁的读写情况下,适合使用这个读写锁。

4、并且只有一个实现类

5、可以做到:先执行完所有写的线程,再执行读操作。

 

没有加锁

  • 自定义缓存,多个线程进行读,多个线程进行写

  • 没有加锁的情况下:

package com.zxh.add;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache cache = new MyCache();

        // 5个写线程
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                cache.put(temp + "", temp + "");
            }, String.valueOf(i)).start();
        }
        // 5个读线程
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                cache.read(temp + "");
            }, String.valueOf(i)).start();
        }

    }
}
/**
 * 自定义缓存
 */
class MyCache{
//    volatile,保证原子性,后面会讲
    private volatile Map<String, String> map = new HashMap<>();

    //
    public void put(String key, String value){
        System.out.println(Thread.currentThread().getName() + "写入" + key);
        map.put(key, value);
        System.out.println(Thread.currentThread().getName() + "写入OK");
    }

    //
    public void read(String key){
        System.out.println(Thread.currentThread().getName() + "读取" + map.get(key));
        System.out.println(Thread.currentThread().getName() + "读取OK");
    }

}

存在问题

1、在还没有写完的情况下,就插入了读操作;

2、一个线程没有写完,被另一写线程插队了。

3、还没有写入,读线程就读取了。

加锁

加了Lock锁的情况

package com.zxh.add;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache2 cache = new MyCache2();

        // 5个写线程
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                cache.put(temp + "", temp + "");
            }, String.valueOf(i)).start();
        }
        // 5个读线程
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                cache.read(temp + "");
            }, String.valueOf(i)).start();
        }

    }
}
/**
 * 自定义缓存
 */
class MyCache2{
    //    volatile,无法保证原子性,后面会讲,但是可以防止指令的重排
    private volatile Map<String, String> map = new HashMap<>();

    Lock lock = new ReentrantLock();

    //
    public void put(String key, String value){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    //
    public void read(String key){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName() + "读取" + key);
            map.get(key);
            System.out.println(Thread.currentThread().getName() + "读取OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

存在问题:

1、没有存放,就进行了读取操作

2、读取的时候,只能有一个线程操作,读完之后,其他线程才能继续,这样效率低,不满足一开始所说的,读可以被多个线程同时操作。

加了ReadWriteLock锁的情况

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache3 cache = new MyCache3();

        // 5个写线程
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                cache.put(temp + "", temp + "");
            }, String.valueOf(i)).start();
        }
        // 5个读线程
        for (int i = 1; i <= 5; i++) {
            final int temp = i;
            new Thread(()->{
                cache.read(temp + "");
            }, String.valueOf(i)).start();
        }

    }
}
/**
 * 自定义缓存,加了ReadWriteLock读写锁
 */
class MyCache3{
    //    volatile,保证原子性,后面会讲
    private volatile Map<String, String> map = new HashMap<>();

    ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); // 读写锁

    //
    public void put(String key, String value){
        readWriteLock.writeLock().lock();   // 写加锁
        try {
            System.out.println(Thread.currentThread().getName() + "写入" + key);
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "写入OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock(); //写解锁
        }

    }

    //
    public void read(String key){
        readWriteLock.readLock().lock();    // 读加锁
        try {
            System.out.println(Thread.currentThread().getName() + "读取" + map.get(key));
            System.out.println(Thread.currentThread().getName() + "读取OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();  // 读解锁
        }

    }

}

可以看到非常完美,先执行完写的线程,再进行读操作;

其次读的操作,是多个线程同时进行的,提高了效率;

猜你喜欢

转载自www.cnblogs.com/zxhbk/p/12960516.html