文档章节

关于ReadWriteLock的一些使用

s
 snecker
发布于 2015/08/15 02:32
字数 1250
阅读 113
收藏 11

最近遇到一个业务场景

  1. 有三个耗时线程。
  2. 线程A、线程B相互独立,并且会周期性执行sql,通过时间 增量获取新数据
  3. 线程C也是增量获取数据,并且操作依赖于线程A和线程B产生的数据; 可以简单理解为:独立同步A表、B表,同步C表的时候需要依赖A、B表的数据,也可以把C表看成A、B表的关联关系表。

如何让这三条线程相互协作呢?

最开始的简单想法是:

1.直接把三条线程的方法体抽出来,合并成一个单线程执行,即先执行A,再执行B(或者2个线程执行A,B)之后执行C线程方法体。

问题:如果是耗时操作,那么有可能出现等到我执行C线程的时候,A或者B数据源有更新,当然C执行的时候是获取不到A或B的最新数据的,那样就有可能导致丢失有效关联关系。而且单线程也无法提升整体性能。

2.利用A、B数据源的最后更新时间,对比C表最后更新时间,取最小值,然后与上次更新时间形成时间差,再同步这个时间差内产生的数据。 缺点:需要准确维护最后更新日期,若丢失时间则需要重新计算

3.利用读写锁来控制同步。A、B线程写数据的时候用writeLock锁住,C中对A、B引用块加读锁,同步用writeLock.condition的 await()、signalAll()方法来控制

重点说下第三种 先让code来说话吧

package com.xx;

/**
 * Created on 2015/8/13.
 */

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestCondition2 {

    /**
     * 场景1:
     * 线程C开始同步,发现依赖的线程A或B数据不全,然后循环等待
     * 场景2:
     * A或B在同步的时候,禁止线程C同步。
     *
     * @param args
     */

    public static void main(String[] args) {
        ReadWriteLock orgReadWriteLock = new ReentrantReadWriteLock();//默认非公平锁
        Lock orgReadLock = orgReadWriteLock.readLock();
        Lock orgWriteLock = orgReadWriteLock.writeLock();
        Condition orgHasDataCond = orgReadWriteLock.writeLock().newCondition();//写锁支持condition,readLock().newCondition() throws UnsupportedOperationException.

        ReadWriteLock invRWLock = new ReentrantReadWriteLock();
        Lock invReadLock = invRWLock.readLock();
        Lock invWriteLock = invRWLock.writeLock();
        Condition invCondition = invWriteLock.newCondition();

        ExecutorService executor = Executors.newFixedThreadPool(4);
        Map mapA = new HashMap<>();
        Map mapB = new HashMap<>();
        Random r = new Random();
        //线程1:专门写A数据
        //线程2:专门写B数据,和A数据是独立的
        //线程3:依赖线程1和线程2
        //1
        Runnable r1 = () -> {
            while (true) {
                orgWriteLock.lock();
                try {
                    mapA.put("A", r.nextInt(10));
                    //signal
                    orgHasDataCond.signalAll();
                } finally {
                    orgWriteLock.unlock();
                }
                System.out.println("线程A等待2s。。。" + mapA.get("A"));
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        //2
        Runnable r2 = () -> {
            while (true) {
                invWriteLock.lock();
                try {
                    mapB.put("B", r.nextInt(20));
                    invCondition.signalAll();
                } finally {
                    invWriteLock.unlock();
                }
                System.out.println("线程B等待1s。。。" + mapB.get("B"));
                try {
                    Thread.sleep(1000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Runnable r3 = () -> {
            while (true) {
                try {
                    //拿到线程A的值
                    Object a = null;
                    //依赖A
                    try {
                        orgReadLock.lock();
                        a = mapA.get("A");
                        System.out.println("线程3取到A的值:" + a);
                    } finally {
                        //unlock
                        orgReadLock.unlock();
                    }

                    try {
                        orgWriteLock.lock();
                        //线程3要求mapA小于5,否则一直等下去
                        while ((int) (a = mapA.get("A")) < 5) {
                            System.out.println("======线程3取到A的值小于5,等待。。。当前a=" + a);
                            orgHasDataCond.await();
                        }
                        System.out.println("【SUCCESSFUL】==========线程3终于取到了A:" + a);
                    } finally {
                        orgWriteLock.unlock();
                    }
                    //依赖B
                    Object b = null;
                    try {
                        invReadLock.lock();
                        b = mapB.get("B");
                        System.out.println("线程3取到B的值:" + b);
                    } finally {
                        //unlock
                        invReadLock.unlock();
                    }

                    try {
                        invWriteLock.lock();
                        //线程3要求mapA小于5,否则一直等下去
                        while ((int) (b = mapB.get("B")) < 15) {
                            System.out.println("======线程3取到B的值小于15,等待大于15。。。当前B=" + b);
                            invCondition.await();
                        }
                        System.out.println("【SUCCESSFUL】==========线程3终于取到了B:" + b);
                    } finally {
                        invWriteLock.unlock();
                    }
//                    orgReadLock.lock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(5000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        //
        executor.execute(r1);
        executor.execute(r2);
        executor.execute(r3);
        executor.shutdown();
    }
}

运行结果

线程B等待1s。。。13
线程A等待2s。。。7
【SUCCESSFUL】==========线程3终于取到了A:7
线程3取到B的值:13
======线程3取到B的值小于15,等待大于15。。。当前B=13
======线程3取到B的值小于15,等待大于15。。。当前B=8
线程B等待1s。。。8
线程B等待1s。。。5
======线程3取到B的值小于15,等待大于15。。。当前B=5
线程A等待2s。。。1
线程B等待1s。。。3
======线程3取到B的值小于15,等待大于15。。。当前B=3
======线程3取到B的值小于15,等待大于15。。。当前B=1
线程B等待1s。。。1
线程A等待2s。。。4
线程B等待1s。。。7
======线程3取到B的值小于15,等待大于15。。。当前B=7
【SUCCESSFUL】==========线程3终于取到了B:15
线程B等待1s。。。15
线程A等待2s。。。5
线程B等待1s。。。1
线程B等待1s。。。7
线程A等待2s。。。1
线程B等待1s。。。17
线程B等待1s。。。16
线程A等待2s。。。4
线程3取到A的值:4
======线程3取到A的值小于5,等待。。。当前a=4

需要注意的是:condition如果和writelock绑定的话需要在writelock持有的情况下调用,否则抛出IllegalMonitorException。 引用官方一句

[IllegalMonitorException]Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.

© 著作权归作者所有

s
粉丝 1
博文 43
码字总数 10092
作品 0
长沙
技术主管
私信 提问
java线程:互斥锁与读写锁

两种互斥锁机制: 1、synchronized 2、ReentrantLock ReentrantLock是jdk5的新特性,采用ReentrantLock可以完全替代替换synchronized传统的锁机制,而且采用ReentrantLock的方式更加面向对象...

_______-
2016/09/02
65
0
22、Java并发性和多线程-Java中的读/写锁

以下内容转自http://ifeve.com/read-write-locks/: 相比Java中的锁(Locks in Java)里Lock实现,读写锁更复杂一些。假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么...

easonjim
2017/06/17
0
0
java并发编程——锁机制

第一部分:synchronized和volatile 锁机制用来保护对象的一致性以及操作的原子性,是实现线程安全的重要手段。线程安全涉及到对象两个重要的状态:共享性和可变性。如果对象是不可变的、线程...

isam
2016/05/27
107
0
第四章-java多线程核心技术-Lock锁-第三篇

Condition实现顺序运行 使用condition对象可以对线程业务进行规划和排序。请看如下代码 输出结果 读写锁的产生 ReentrantLock锁是完全互斥的锁,即同一时间内只有一个线程执行锁后面的方法,...

简心
2018/09/06
25
2
Java 多线程:Lock接口(接口方法分析,ReentrantLock,ReadWriteLock

前言 *** 当我们了解了多线程生成的原因之后,会有相应的解决办法,最典型的就是 synchronized 和 lock。lock可以说是 synchronized 的一个替代品,synchronized 能做的事,lock 基本都可以做...

icanos
2016/07/21
19
0

没有更多内容

加载失败,请刷新页面

加载更多

006-Docker中导出单个或多个tar包

docker中导出单个镜像和多个镜像的tar包 docker save [images] > [name.tar] docker save [images] [images] > [name.tar]...

伟大源于勇敢的开始
今天
6
0
Kotlin基础语法学习

安装好安卓studio,以及插件支持Kotlin 就可以在创建项目的时候选择 Kotlin语言了。 https://www.jianshu.com/p/4ab13691d681 参考手册: https://www.runoob.com/kotlin/otlin-android-setu...

T型人才追梦者
今天
4
0
java实现简单计算器

1.概述 之前作者写过一篇文章,也是关于计算器的,用的是C++与Qt,链接在这里 这次用java的swing写的(这差距好像有点大,好吧是qt太强了). 先上图: 2.UI 总体布局使用流布局. (1)文本框 文本框就...

Blueeeeeee
今天
4
0
纯CSS实现DIV悬浮(固定位置)

纯CSS实现的DIV悬浮效果(固定位置),兼容常用的浏览器:IE8、360、FireFox、Chrome、Safari、Opera、傲游、搜狗、世界之窗等。效果如下: 实现代码: <!DOCTYPE html> <html> <head> <meta ...

独钓渔
今天
6
0
OSChina 周二乱弹 —— 给我来个女菩萨

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @这次装个文艺青年吧 :#今日歌曲推荐#分享XXXTENTACION/Travis Barker的单曲《Pain = BESTFRIEND》: 《Pain = BESTFRIEND》- XXXTENTACION/...

小小编辑
今天
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部