基本线程同步(六)使用读/写锁同步数据访问

使用读/写锁同步数据访问

锁所提供的最重要的改进之一就是ReadWriteLock接口和唯一 一个实现它的ReentrantReadWriteLock类。这个类提供两把锁,一把用于读操作和一把用于写操作。同时可以有多个线程执行读操作,但只有一个线程可以执行写操作。当一个线程正在执行一个写操作,不可能有任何线程执行读操作。

在这个指南中,你将会学习如何使用ReadWriteLock接口实现一个程序,使用它来控制访问一个存储两个产品价格的对象。

准备工作…

你应该事先阅读使用Lock同步代码块的指南,才能更好的理解这个食谱。

如何做…

按以下步骤来实现的这个例子:

1.创建PricesInfo类,用它来存储两个产品价格的信息。

1 public class PricesInfo {

2.声明两个double类型的属性,分别命名为price1和price2。

1 private double price1;
2 private double price2;

3.声明一个名为lock的ReadWriteLock对象。

1 private ReadWriteLock lock;

4.实现类的构造器,初始化这三个属性。其中,对于lock属性,我们创建一个新的ReentrantReadWriteLock对象。

1 public PricesInfo(){
2 price1=1.0;
3 price2=2.0;
4 lock=new ReentrantReadWriteLock();
5 }

5.实现getPrice1()方法,用它来返回price1属性的值。它使用读锁来控制这个属性值的访问。

1 public double getPrice1() {
2 lock.readLock().lock();
3 double value=price1;
4 lock.readLock().unlock();
5 return value;
6 }

6.实现getPrice2()方法,用它来返回price2属性的值。它使用读锁来控制这个属性值的访问。

1 public double getPrice2() {
2 lock.readLock().lock();
3 double value=price2;
4 lock.readLock().unlock();
5 return value;
6 }

7.实现setPrices()方法,用来建立这两个属性的值。它使用写锁来控制对它们的访问。

1 public void setPrices(double price1, double price2) {
2 lock.writeLock().lock();
3 this.price1=price1;
4 this.price2=price2;
5 lock.writeLock().unlock();
6 }

8.创建Reader类,并指定它实现Runnable接口。这个类实现了PricesInfo类属性值的读者。

1 public class Reader implements Runnable {

9.声明一个PricesInfo对象,并且实现Reader类的构造器来初始化这个对象。

1 private PricesInfo pricesInfo;
2 public Reader (PricesInfo pricesInfo){
3 this.pricesInfo=pricesInfo;
4 }

10.实现Reader类的run()方法,它读取10次两个价格的值。

1 @Override
2 public void run() {
3 for (int i=0; i<10; i++){
4 System.out.printf("%s: Price 1: %f\n", Thread.
5 currentThread().getName(),pricesInfo.getPrice1());
6 System.out.printf("%s: Price 2: %f\n", Thread.
7 currentThread().getName(),pricesInfo.getPrice2());
8 }
9 }

11.创建Writer类,并指定它实现Runnable接口。这个类实现了PricesInfo类属性值的修改者。

1 public class Writer implements Runnable {

12.声明一个PricesInfo对象,并且实现Writer类的构造器来初始化这个对象。

1 private PricesInfo pricesInfo;
2 public Writer(PricesInfo pricesInfo){
3 this.pricesInfo=pricesInfo;
4 }

13.实现run()方法,它修改了三次两个价格的值,并且在每次修改之后睡眠2秒。

01 @Override
02 public void run() {
03 for (int i=0; i<3; i++) {
04 System.out.printf("Writer: Attempt to modify the
05 prices.\n");
06 pricesInfo.setPrices(Math.random()*10, Math.random()*8);
07 System.out.printf("Writer: Prices have been modified.\n");
08 try {
09 Thread.sleep(2);
10 } catch (InterruptedException e) {
11 e.printStackTrace();
12 }
13 }
14 }

14.通过创建类名为Main,且包括main()方法来实现这个示例的主类。

1 public class Main {
2 public static void main(String[] args) {

15.创建一个PricesInfo对象。

1 PricesInfo pricesInfo=new PricesInfo();

16.创建5个Reader对象,并且用5个线程来执行它们。

1 Reader readers[]=new Reader[5];
2 Thread threadsReader[]=new Thread[5];
3 for (int i=0; i<5; i++){
4 readers[i]=new Reader(pricesInfo);
5 threadsReader[i]=new Thread(readers[i]);
6 }

17.创建一个Writer对象,并且用线程来执行它。

1 Writer writer=new Writer(pricesInfo);
2 Thread threadWriter=new Thread(writer);

18.启动这些线程。

1 for (int i=0; i<5; i++){
2 threadsReader[i].start();
3 }
4 threadWriter.start();

它是如何工作的…

在以下截图中,你可以看到执行这个例子的一个部分输出:


正如我们前面提及到的,ReentrantReadWriteLock类有两把锁,一把用于读操作,一把用于写操作。用于读操作的锁,是通过在 ReadWriteLock接口中声明的readLock()方法获取的。这个锁是实现Lock接口的一个对象,所以我们可以使用lock(), unlock() 和tryLock()方法。用于写操作的锁,是通过在ReadWriteLock接口中声明的writeLock()方法获取的。这个锁是实现Lock接 口的一个对象,所以我们可以使用lock(), unlock() 和tryLock()方法。确保正确的使用这些锁,使用它们与被设计的目的是一样的,这是程序猿的职责。当你获得Lock接口的读锁时,不能修改这个变量的值。否则,你可能会有数据不一致的错误。

参见

  • 在第2章,基本线程同步中使用Lock同步代码块的指南。
  • 在第8章,测试并发应该程序中监控Lock接口的指南。
时间: 2024-07-28 15:28:12

基本线程同步(六)使用读/写锁同步数据访问的相关文章

Java多线程编程中线程锁与读写锁的使用示例_java

线程锁LockLock  相当于 当前对象的 Synchronized import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /* * Lock lock = new ReentrantLock(); * lock.lock(); lock.unLock(); * 类似于 synchronized,但不能与synchronized 混用 */ public class Lo

非一致性内存访问的读写锁

原文地址,译文地址,译者: 李杰聪,校对:郑旭东 原文作者: Irina Calciu         Brown University        irina@cs.brown.edu Dave Dice          Oracle Labs             dave.dice@oracle.com Yossi Lev           Oracle Labs             yossi.lev@oracle.com Victor Luchangco    Oracle

java多线程:并发包中ReentrantReadWriteLock读写锁的原理

一:读写锁解决的场景问题--->数据的读取频率远远大于写的频率的场景,就可以使用读写锁.二:读写锁的结构--->用state一个变量.将其转化成二进制,前16位为高位,标记读线程获取锁的次数.后16位为低位,标记写线程获取锁的次数.--->读写锁需要解决的冲突:读/写冲突,写/写冲突.读/读之间无冲突.--->当有写线程获取锁的时候.state的二进制表现,低位有数字,高位全是0.当有读线程获取锁的时候,state的二进制表现,低位全是0,高位有数字.--->如何获取读线获取

嵌入式 互斥锁和读写锁区别

  /*  * 线程同步--互斥量  * 创建两个线程,使用互斥量使任一时刻只有一个线程对全局变量进行 操作  * Lzy 2011-6-19  */ #include <stdio.h> #include <stdlib.h> #include <pthread.h> pthread_mutex_t mutex;                    /* 定义 互斥量 */ int x;                                     /* 

C#使用读写锁三行代码简单解决多线程并发的问题_C#教程

在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三方日志插件,也可以选择使用数据库,还可以自己写个简单的方法把错误信息记录到日志文件. 选择最后一种方法实现的时候,若对文件操作与线程同步不熟悉,问题就有可能出现了,因为同一个文件并不允许多个线程同时写入,否则会提示"文件正在由另一进程使用,因此该进程无法访问此文件". 这是文件的并发写入问题,就需要用到线程同步.而微软也给线程同步提供了一些相关的类可以达到这样的目的,本文使用到的 System.Thr

pthread_rwlock_t读写锁函数说明

转:http://www.cnblogs.com/renxinyuan/p/3875659.html 索引:  初始化一个读写锁pthread_rwlock_init 读锁定读写锁      pthread_rwlock_rdlock 非阻塞读锁定 pthread_rwlock_tryrdlock 写锁定读写锁      pthread_rwlock_wrlock 非阻塞写锁定      pthread_rwlock_trywrlock 解锁读写锁         pthread_rwlock_

多线程,读写锁

问题描述 请教个问题,在多线程运用中,如果只加写锁,没有加读锁,那么在写的过程中,读线程可不可以读数据. 解决方案 解决方案二:读线程可用.解决方案三:如果你不加读锁,那么就不会受到写锁的限制.也就是说读线程可以读数据.看下面我写的简单例子importjava.util.concurrent.locks.ReentrantReadWriteLock;importjava.util.concurrent.locks.Lock;publicclassTestReadWriteLock{publics

UNIX环境高级编程:线程同步之读写锁及属性

读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 互斥量要么是锁住状态要么是不加锁状态,而且一次只有一个线程可以对其加锁.读写锁可以有三种状态:读模式下的加锁状态,写模式下的加锁状态,不加锁状态. 一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁. 当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁(读或写

UNIX环境高级编程:线程同步之互斥锁、读写锁和条件变量

一.使用互斥锁 1.初始化互斥量 pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥量 int pthread_mutex_init(pthread_mutex_t*mutex,pthread_mutexattr_t*attr);//动态初始化互斥量 int pthread_mutex_destory(pthread_mutex_t*mutex);//撤销互斥量 不能拷贝互斥量变量,但可以拷贝指向互斥量的指针,这样就可以使多个函数