您的位置:首页 > 编程语言 > Java开发

java并发编程实战手册第二章使用读写锁实现同步数据访问

2015-04-15 18:38 441 查看
[code]Java并发编程实战手册第二章关于锁的问题。


2.6使用读写锁实现同步数据访问

通过本范例学习ReadWriteLock和实现类,ReentrantReadWriteLock,该类有两个锁一个是读操作锁,一个是写操作锁。读操作锁可以允许多个线程同时访问,写操作锁只允许一个线程进行。当写操作执行的时候,读操作不能执行

1. 创建PriceInfo,Reader,Writer,Main.

1. PriceInfo.java

[code]1.  PriceInfo.java
package cn.fans.chapter2.six;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 
 * @author fcs
 * @date 2015-4-12
 * 描述:使用读写锁实现同步访问
 * 说明:使用ReadWriteLock接口。
 */
public class PricesInfo {
    private double price1;
    private double price2;
    private ReadWriteLock lock;
    public PricesInfo(){
        price1 = 1.0;
        price2 = 2.0;
        lock = new ReentrantReadWriteLock();
    }

    /**
     * 
     * 作者:fcs
     * 描述:使用锁机制进行读操作
     * 说明:
     * 返回:price1
     * 参数:
     * 时间:2015-4-12
     */
    public double getPrice1(){
        double value;
        lock.readLock().lock();
        try{
            value = price1;
            System.out.printf("%s: price 1 : %f\n",Thread.currentThread().getName(),price1);

        }finally{
            lock.readLock().unlock();
        }

        return value;
    }

    /**
     * 
     * 作者:fcs
     * 描述:使用锁机制进行读操作
     * 说明:
     * 返回:price2
     * 参数:
     * 时间:2015-4-12
     */
    public double getPrice2(){
        double value;
        lock.readLock().lock();
        try{
            value = price2;
            System.out.printf("%s Price 2 : %f\n ",Thread.currentThread().getName(),price2);
        }finally{
            lock.readLock().unlock();
        }

        return value;
    }

    /**
     * 
     * 作者:fcs
     * 描述:使用锁机制进行写操作
     * 说明:
     * 返回:
     * 参数:price1, price2
     * 时间:2015-4-12
     */
    public void setPrice(double price1,double price2){
        lock.writeLock().lock();
        System.out.printf("Writer: Attempt to modify the prices.\n");

        try{
            this.price1 = price1;
            this.price2 = price2;
        }finally{
            lock.writeLock().unlock();
            System.out.println("Writer:price have been modified.");

        }
    }
}


[code]package cn.fans.chapter2.six;
/**
 * 
 * @author fcs
 * @date 2015-4-12
 * 描述:读线程
 * 说明:
 */
public class Reader implements  Runnable {
    private PricesInfo pricesInfo;

    public Reader(PricesInfo pricesInfo) {
        this.pricesInfo = pricesInfo;
    }

    @Override
    public void run() {
        for(int i =0;i<10;i++){
            pricesInfo.getPrice1();
            pricesInfo.getPrice2();
        }
    }
}


[code]package cn.fans.chapter2.six;

/**
 * 
 * @author fcs
 * @date 2015-4-12
 * 描述:写线程
 * 说明:
 */
public class Writer  implements  Runnable {
    private PricesInfo pricesInfo;

    public Writer(PricesInfo pricesInfo) {
        this.pricesInfo = pricesInfo;
    }

    /**
     * 循环修改两个价格5次,每次修改后线程将休眠2秒钟
     */
    @Override
    public void run() {
        for(int  i=0;i< 5;i++){
            pricesInfo.setPrice(Math.random()*10, Math.random()*10);
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


[code]package cn.fans.chapter2.six;

public class Main {
    public static void main(String[] args) {
        PricesInfo  pricesInfo = new PricesInfo();
        Reader readers[] = new Reader[5];
        Thread treader [] = new Thread[5];
        for(int  i =0;i<5;i++){
            readers [i] = new Reader(pricesInfo);
            treader[i] = new Thread(readers[i]);
        }

        Writer writer = new Writer(pricesInfo);
        Thread wthread = new Thread(writer);
        for(int i = 0;i < 5;i++){
            treader[i].start();
        }
        wthread.start();
    }
}


创建5个读线程,一个写线程,读线程不互斥,写线程写的时候,读线程读到的信息必须是写线程写完后的新数据。这里如果按照书上的代码,可能会出现非常令人迷惑的输出,关键在与Writer线程中的run方法多了两条输出语句,这两条应该在priceInfo中的setPrice方法中的,我在并发编程网上看到有人说要放在这里,同样csdn上也获得了相同的指导,在实际的运行过程中才跟书上的一致。

深入分析就是Writer线程是使用for循环进行写入的,也就是说在for循环中的两条输出语句中间执行priceinfo.setPrice方法,是有延迟的,导致每次修改前后两条输出语句并不是连续输出的,这是因为在输出第一条语句的时候,写线程正在获取锁,其他读线程可能正在读写线程上一次修改的值,当输出第二条语句的时候,有的读线程读到新的值,而有的读到旧的值。这就出现了一种幻觉,认为读线程读到了脏数据。所以应该将这两条放到setPrice中的lock(),和unlock()方法下。这样才会输出两条连续的提示语句,然后读线程会在输出语句后读出一致的值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: