ReentrantReadWriteLock读写锁

世上唯一不能复制的是时间,唯一不能重演的是人生,唯一不劳而获的是年龄。该怎么走,过什么样的生活,全凭自己的选择和努力。人生很贵,请别浪费!与智者为伍,与良善者同行。ReentrantReadWriteLock读写锁,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

ReentrantReadWriteLock读写锁

乐观锁和悲观锁

乐观锁

乐观锁,就是给需要共享的数据,添加一个版本号version,例如1,每次有线程更新共享数据后,version+1,每次线程进行数据更新时,要比较当前线程持有的数据的版本号,相等则修改,不相等则不修改,支持并发访问。

悲观锁

悲观锁,就是每次只能有一个线程,访问共享的数据,其他线程都阻塞,只有当前线程结束,才会释放锁,其他线程中的一个才能访问,不支持并发访问。

表锁和行锁

表锁

线程涉及到数据库的修改时,其他线程不能修改整个表中的任意行数据,就是表锁,表锁不会出现行锁。

行锁

线程涉及到数据库的修改时,只锁当前的一行,是行锁,可能会出现死锁。

读写锁

读锁是共享锁,写锁是独占锁。都可能出现死锁。
读写锁,一个资源可以被多个读线程访问,或者一个写线程访问,但是不能同时存在读写线程,读写是互斥的,读读是共享的。

案例及代码实现
//1.定义资源类
class MyCache {

    //volatile关键字,共享的数据,在一个线程修改后,被其他线程访问到
    private volatile HashMap<String, Object> hashMap = new HashMap<>();

    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    //2.定义操作资源类的方法
    public Object get(String key) {
        rwLock.readLock().lock();//读锁
        Object result = null;
        try {
            System.out.println(Thread.currentThread().getName() + "正在读取值" + key);

            TimeUnit.MILLISECONDS.sleep(300);
            result = hashMap.get(key);
            System.out.println(Thread.currentThread().getName() + "读取值完成" + key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rwLock.readLock().unlock();
        }
        return result;
    }

    public void put(String key, Object value) {
        rwLock.writeLock().lock();//写锁
        try {
            System.out.println(Thread.currentThread().getName() + "正在添加值" + key);
            TimeUnit.MILLISECONDS.sleep(300);
            hashMap.put(key, value);
            System.out.println(Thread.currentThread().getName() + "添加值完成" + key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rwLock.writeLock().unlock();
        }

    }


}

public class ReadWriteLockDemo {
    public static void main(String[] args) {
        MyCache cache = new MyCache();
        
        //创建线程,向缓存中添加值
        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(() -> {
                cache.put(num + "", num);
            }, String.valueOf(i)).start();
        }

        //创建线程,向缓存中获取值
        for (int i = 0; i < 5; i++) {
            final int num = i;
            new Thread(() -> {
                cache.get(num + "");
            }, String.valueOf(i)).start();
        }

    }
}

读写锁的演变

ReentrantReadWriteLock读写锁

读写锁的降级

ReentrantReadWriteLock读写锁

降级案例及代码
/**
 * @author 长名06
 * @version 1.0
 * 读写锁降级演示
 */
public class ReadWriteLockDownLevelDemo {
    public static void main(String[] args) {
        ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
        ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();//写锁
        ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();//读锁
		//先读后写,获取读锁后,就获取不到写锁,线程阻塞

        //1.获取写锁
        writeLock.lock();
        System.out.println("获取写锁");

        //2.获取读锁
        readLock.lock();
        System.out.println("获取读锁");

        //3.释放写锁
        writeLock.unlock();

        //4.释放读锁
        readLock.unlock();
    }
}

小结

  • 1.在线程持有读锁的情况下,该线程不能取得写锁,因为获取写锁时,如果写锁对应的读锁被占用,就马上获取失败,不管读锁是否是当前线程持有(原因,此写锁对应的读锁被线程持有,证明有线程正在读取数据,这是为了避免出现幻读现象)。
  • 2.在线程持有写锁的情况下,该线程可以继续获取读锁。获取读锁时,如果发现写锁被占用,只有写锁没有被当前线程占用的情况下才会获取失败。
  • 原因,读锁是共享锁,即当某个线程获取读锁时,可能有其他线程同时也在持有读锁;而对于已获取写锁的线程,它一定独占了写锁因此可以继续让其获取读锁,当该线程同时获取了写锁和读锁时,还可以先释放写锁继续持有读锁,这样就称为写锁的降级。
    只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/213053.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!