文档章节

Java并发编程初级篇(十四):使用读写所实现同步机制

阿拉德大陆的魔法师
 阿拉德大陆的魔法师
发布于 2016/11/25 11:29
字数 939
阅读 16
收藏 0
点赞 0
评论 0

Java API除了提供Lock()接口之外,还为我们提供了一个读写锁接口ReadWriteLock,使用这个锁的实现类ReentrantReadWriteLock可以让我们把读锁和写锁进行分离,对同步数据进行修改的时候使用写锁,这时候其他需要获取写锁的线程会被挂起,同时使用读锁的线程也会被挂起。而读取数据的时候使用读锁,这时候使用读锁的线程可以并发访问,以提高效率。

public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     *
     * @return the lock used for reading.
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     *
     * @return the lock used for writing.
     */
    Lock writeLock();
}

我们模拟一个修改价格的例子,来看一下读锁与写锁是如何使用的。

创建一个价格类,里面两个商品的价格以及一个读写锁。在修改价格的方法里我们使用写锁,在读取商品价格的方法里我们使用读锁。修改商品价方法休眠两秒来模拟修改价格的过程,并打印修改价格信息。

public class PriceInfo {
    private double price1;
    private double price2;
    private ReadWriteLock lock;

    public PriceInfo() {
        price1 = 1.0;
        price2 = 2.0;
        lock = new ReentrantReadWriteLock();
    }

    public double getPrice1() {
        lock.readLock().lock();
        double value = price1;
        lock.readLock().unlock();
        return price1;
    }

    public double getPrice2() {
        lock.readLock().lock();
        double value = price2;
        lock.readLock().unlock();
        return price2;
    }

    public void setPrice(double price1, double price2) {
        lock.writeLock().lock();
        System.out.printf("Writer: Attemp to modify the price! Price1:%f Price2:%f\n", price1, price2);
        this.price1 = price1;
        this.price2 = price2;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("Writer: Price has been modified: Price1:%f Price2:%f\n", price1, price2);
        lock.writeLock().unlock();
    }
}

创建一个价格修改线程,随机休眠一定时间后修改价格。

public class Writer implements Runnable{
    private PriceInfo priceInfo;

    public Writer(PriceInfo priceInfo) {
        this.priceInfo = priceInfo;
    }

    @Override
    public void run() {
        double price1 = Math.random() * 10;
        double price2 = Math.random() * 8;

        try {
            Thread.sleep((long) (Math.random() * 10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        priceInfo.setPrice(price1, price2);
    }
}

创建一个价格读取线程,每次读取两个商品的价格并打印。

public class Reader implements Runnable {
    private PriceInfo priceInfo;

    public Reader(PriceInfo priceInfo) {
        this.priceInfo = priceInfo;
    }

    @Override
    public void run() {
        Date date = new Date();
        System.out.printf("%s: Price1 %f .%s\n",
                Thread.currentThread().getName(), priceInfo.getPrice1(), date);
        System.out.printf("%s: Price2 %f .%s\n",
                Thread.currentThread().getName(), priceInfo.getPrice2(), date);
    }
}

创建主方法类,启动三个价格修改线程。然后每个两秒启动一个线程读取商品价格。

public class Main {
    public static void main(String[] args) {
        PriceInfo priceInfo = new PriceInfo();

        for (int i = 0; i < 3; i++) {
            Thread threadWriter = new Thread(new Writer(priceInfo));
            threadWriter.start();
        }

        while (true) {
            new Thread(new Reader(priceInfo)).start();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

查看控制台日志,每次读取价格都是修改价格之后的新价格,并且在修改价格的2秒内,读取价格线程处于挂起状态。

Thread-3: Price1 1.000000 .Fri Nov 25 11:16:35 CST 2016
Thread-3: Price2 2.000000 .Fri Nov 25 11:16:35 CST 2016
Writer: Attemp to modify the price! Price1:9.655775 Price2:4.031177
Writer: Price has been modified: Price1:9.655775 Price2:4.031177
Thread-4: Price1 9.655775 .Fri Nov 25 11:16:37 CST 2016
Thread-4: Price2 4.031177 .Fri Nov 25 11:16:37 CST 2016
Thread-5: Price1 9.655775 .Fri Nov 25 11:16:39 CST 2016
Thread-5: Price2 4.031177 .Fri Nov 25 11:16:39 CST 2016
Writer: Attemp to modify the price! Price1:2.347803 Price2:2.088409
Writer: Price has been modified: Price1:2.347803 Price2:2.088409
Thread-6: Price1 2.347803 .Fri Nov 25 11:16:41 CST 2016
Thread-6: Price2 2.088409 .Fri Nov 25 11:16:41 CST 2016
Thread-7: Price1 2.347803 .Fri Nov 25 11:16:43 CST 2016
Thread-7: Price2 2.088409 .Fri Nov 25 11:16:43 CST 2016
Writer: Attemp to modify the price! Price1:0.981288 Price2:6.281034
Writer: Price has been modified: Price1:0.981288 Price2:6.281034
Thread-8: Price1 0.981288 .Fri Nov 25 11:16:45 CST 2016
Thread-8: Price2 6.281034 .Fri Nov 25 11:16:45 CST 2016
Thread-9: Price1 0.981288 .Fri Nov 25 11:16:47 CST 2016
Thread-9: Price2 6.281034 .Fri Nov 25 11:16:47 CST 2016
Thread-10: Price1 0.981288 .Fri Nov 25 11:16:49 CST 2016
Thread-10: Price2 6.281034 .Fri Nov 25 11:16:49 CST 2016
Thread-11: Price1 0.981288 .Fri Nov 25 11:16:51 CST 2016
Thread-11: Price2 6.281034 .Fri Nov 25 11:16:51 CST 2016

 

© 著作权归作者所有

共有 人打赏支持
阿拉德大陆的魔法师
粉丝 20
博文 91
码字总数 83019
作品 0
西城
程序员
【Java并发专题】27篇文章详细总结Java并发基础知识

努力的意义,就是,在以后的日子里,放眼望去全是自己喜欢的人和事! github:https://github.com/CL0610/Java-concurrency,欢迎题issue和Pull request。所有的文档都是自己亲自码的,如果觉...

你听___ ⋅ 05/06 ⋅ 0

[Java 并发编程] 集合框架之 同步容器类 & 并发容器类

吾生也有涯,而知也无涯。———《庄子》 通过上一篇文章,我们已经知道设计一个线程安全类的原则和步骤,以及在设计过程中我们应当注意的细节。实际上,Java 的集合库包含了线程安全集合和非...

seaicelin ⋅ 05/25 ⋅ 0

Java 编程之美:并发编程基础晋级篇

本文来自作者 加多 在 GitChat 上分享 「Java 并发编程之美:并发编程基础晋级篇」 编辑 | Mc Jin 借用 Java 并发编程实践中的话,编写正确的程序并不容易,而编写正常的并发程序就更难了! ...

gitchat ⋅ 04/18 ⋅ 0

Java 多线程编程 — 锁优化2

Java多线程编程-(13)- 关于锁优化的几点建议 一、背景 在《 Java多线程编程-(11)-从volatile和synchronized的底层实现原理看Java虚拟机对锁优化所做的努力》 这一篇文章中,我们大致介绍...

晨猫 ⋅ 04/26 ⋅ 0

Java 编程之美:并发编程高级篇之一

本文来自作者 追梦 在 GitChat 上分享 「Java 编程之美:并发编程高级篇之一」 编辑 | 工藤 前言 借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了。 ...

gitchat ⋅ 05/24 ⋅ 0

java线程同步之volatile

volatile的概念: volatile与synchronized关键字是多线程并发编程中非常重要的知识点,通常被用于修饰变量。相比于synchroinized来说,volatile要轻量很多,执行的成本会更低。原因是volatil...

lotnip ⋅ 05/24 ⋅ 0

Java并发机制及锁的实现原理

Java并发编程概述 并发编程的目的是为了让程序运行得更快,但是,并不是启动更多的线程就能让程序最大限度地并发执行。在进行并发编程时,如果希望通过多线程执行任务让程序运行得更快,会面...

烂猪皮 ⋅ 05/11 ⋅ 0

悲观的并发策略——synchronized互斥锁

互斥锁是最常见的同步手段,在并发过程中,当多条线程对同一个共享数据竞争时,它保证共享数据同一时刻只能被一条线程使用,其他线程只有等到锁释放后才能重新进行竞争。 对于Java开发人员,...

wangyangzhizhou ⋅ 04/16 ⋅ 0

面试必看!2018年4月份阿里最新的java程序员面试题目

目录 技术一面(23问) 技术二面(3大块) 性能优化(21点) 项目实战(34块) JAVA方向技术考察点(15点) JAVA开发技术面试中可能问到的问题(17问) 阿里技术面试1 1.Java IO流的层次结构...

美的让人心动 ⋅ 04/16 ⋅ 0

java面试必备之ThreadLocal

按照传统的经验,如果某个对象是非线程安全的,在多线程环境下对象的访问需要采用synchronized进行同步。但是模板类并未采用线程同步机制,因为线程同步会降低系统的并发性能,此外代码同步解...

编程老司机 ⋅ 05/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JavaScript零基础入门——(八)JavaScript的数组

JavaScript零基础入门——(八)JavaScript的数组 欢迎大家回到我们的JavaScript零基础入门,上一节课我们讲了有关JavaScript正则表达式的相关知识点,便于大家更好的对字符串进行处理。这一...

JandenMa ⋅ 今天 ⋅ 0

sbt网络问题解决方案

转自:http://dblab.xmu.edu.cn/blog/maven-network-problem/ cd ~/.sbt/launchers/0.13.9unzip -q ./sbt-launch.jar 修改 vi sbt/sbt.boot.properties 增加一个oschina库地址: [reposit......

狐狸老侠 ⋅ 今天 ⋅ 0

大数据,必须掌握的10项顶级安全技术

我们看到越来越多的数据泄漏事故、勒索软件和其他类型的网络攻击,这使得安全成为一个热门话题。 去年,企业IT面临的威胁仍然处于非常高的水平,每天都会看到媒体报道大量数据泄漏事故和攻击...

p柯西 ⋅ 今天 ⋅ 0

Linux下安装配置Hadoop2.7.6

前提 安装jdk 下载 wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.7.6/hadoop-2.7.6.tar.gz 解压 配置 vim /etc/profile # 配置java环境变量 export JAVA_HOME=/opt/jdk1......

晨猫 ⋅ 今天 ⋅ 0

crontab工具介绍

crontab crontab 是一个用于设置周期性被执行的任务工具。 周期性执行的任务列表称为Cron Table crontab(选项)(参数) -e:编辑该用户的计时器设置; -l:列出该用户的计时器设置; -r:删除该...

Linux学习笔记 ⋅ 今天 ⋅ 0

深入Java多线程——Java内存模型深入(2)

5. final域的内存语义 5.1 final域的重排序规则 1.对于final域,编译器和处理器要遵守两个重排序规则: (1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用...

江左煤郎 ⋅ 今天 ⋅ 0

面试-正向代理和反向代理

面试-正向代理和反向代理 Nginx 是一个高性能的反向代理服务器,但同时也支持正向代理方式的配置。

秋日芒草 ⋅ 今天 ⋅ 0

Spring 依赖注入(DI)

1、Setter方法注入: 通过设置方法注入依赖。这种方法既简单又常用。 类中定义set()方法: public class HelloWorldOutput{ HelloWorld helloWorld; public void setHelloWorld...

霍淇滨 ⋅ 昨天 ⋅ 0

马氏距离与欧氏距离

马氏距离 马氏距离也可以定义为两个服从同一分布并且其协方差矩阵为Σ的随机变量之间的差异程度。 如果协方差矩阵为单位矩阵,那么马氏距离就简化为欧氏距离,如果协方差矩阵为对角阵,则其也...

漫步当下 ⋅ 昨天 ⋅ 0

聊聊spring cloud的RequestRateLimiterGatewayFilter

序 本文主要研究一下spring cloud的RequestRateLimiterGatewayFilter GatewayAutoConfiguration @Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMi......

go4it ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部