【转】Java线程:新特征-锁(2)

说到ReentrantReadWriteLock,首先要做的是与ReentrantLock划清界限.它和后者都是单独的实现,彼此之间没有继承或实现的关系.然后就是总结这个锁机制的特性了:

  1. 重入方面其内部的WriteLock可以获取ReadLock,但是反过来ReadLock想要获得WriteLock则永远都不要想。
  2. WriteLock可以降级为ReadLock,顺序是:先获得WriteLock再获得ReadLock,然后释放WriteLock,这时候线程将保持Readlock的持有。反过来ReadLock想要升级为WriteLock则不可能,为什么?参看(1)。
  3. ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥。这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量。
  4. 不管是ReadLock还是WriteLock都支持Interrupt,语义与ReentrantLock一致。
  5. readLock只有释放后,writeLock才能获得锁。
  6. readLock在没有被释放的时候可以被多个线程同时读取,此时还可以重入writeLock锁。
  7. writeLock在没有被释放的时候其他锁不能进入,也不能重入readLock锁,直到writeLock被解锁 。

 

ReentrantReadWriteLock会使用两把锁来解决问题:一个读锁,一个写锁。

  • 线程进入读锁的前提条件:
          没有其他线程的写锁
          没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。
  • 线程进入写锁的前提条件:
          没有其他线程的读锁
          没有其他线程的写锁
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* Java线程:锁
*
* @author leizhimin 2009-11-5 10:57:29
*/
public class LockT2 {
    public static void main(String[] args) {
        //创建并发访问的账户
        MyCount2 myCount = new MyCount2("95599200901215522", 10000);
        //创建一个锁对象
        ReadWriteLock lock = new ReentrantReadWriteLock(false);
        //创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(10);
        //创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊
        User2 u1 = new User2("张三", myCount, -4000, lock, false);
        User2 u2 = new User2("李四", myCount, 6000, lock, false);
        User2 u3 = new User2("王五", myCount, -8000, lock, false);
        User2 u4 = new User2("孙六", myCount, 800, lock, false);
        User2 u5 = new User2("赵七", myCount, 0, lock, true);

        //在线程池中执行各个用户的操作
        pool.execute(u1);
        pool.execute(u2);
        pool.execute(u3);
        pool.execute(u4);
        pool.execute(u5);
        //关闭线程池
        pool.shutdown();
    }
}
/**
* 信用卡的用户
*/
class User2 implements Runnable {
    private String name; //用户名 
    private MyCount2 myCount; //所要操作的账户
    private int iocash; //操作的金额,当然有正负之分了
    private ReadWriteLock myLock; //执行操作所需的锁对象
    private boolean ischeck; //是否查询

    User2(String name, MyCount2 myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {
        this.name = name;
        this.myCount = myCount;
        this.iocash = iocash;
        this.myLock = myLock;
        this.ischeck = ischeck;
    }

    public void run() {
        if (ischeck) {
            //获取读锁
            myLock.readLock().lock();

            System.out.println("读:" + name + "正在查询" + myCount + "账户,当前金额为" + myCount.getCash());
            //释放读锁
            myLock.readLock().unlock();
        }
        else {
            //获取写锁
            myLock.writeLock().lock();
//执行现金业务 
            System.out.println("写:" + name + "正在操作" + myCount + "账户,金额为" + iocash + ",当前金额为" + myCount.getCash());
            myCount.setCash(myCount.getCash() + iocash);
            System.out.println("写:" + name + "操作" + myCount + "账户成功,金额为" + iocash + ",当前金额为" + myCount.getCash());
            //释放写锁
            myLock.writeLock().unlock();
        }
    }
}
/**
* 信用卡账户,可随意透支 
*/
class MyCount2 {
    private String oid; //账号
    private int cash; //账户余额 

    MyCount2(String oid, int cash) {
        this.oid = oid;
        this.cash = cash;
    }

    public String getOid() {
        return oid;
    }

    public void setOid(String oid) {
        this.oid = oid;
    }

    public int getCash() {
        return cash;
    }

    public void setCash(int cash) {
        this.cash = cash;
    }

    @Override
    public String toString() {
        return "MyCount{" + "oid='" + oid + '\'' + ", cash=" + cash + '}';
    }
}

 打印结果:
写:张三正在操作MyCount{oid='95599200901215522', cash=10000}账户,金额为-4000,当前金额为10000
写:张三操作MyCount{oid='95599200901215522', cash=6000}账户成功,金额为-4000,当前金额为6000
写:孙六正在操作MyCount{oid='95599200901215522', cash=6000}账户,金额为800,当前金额为6000
写:孙六操作MyCount{oid='95599200901215522', cash=6800}账户成功,金额为800,当前金额为6800
写:李四正在操作MyCount{oid='95599200901215522', cash=6800}账户,金额为6000,当前金额为6800
写:李四操作MyCount{oid='95599200901215522', cash=12800}账户成功,金额为6000,当前金额为12800
写:王五正在操作MyCount{oid='95599200901215522', cash=12800}账户,金额为-8000,当前金额为12800
写:王五操作MyCount{oid='95599200901215522', cash=4800}账户成功,金额为-8000,当前金额为4800
读:赵七正在查询MyCount{oid='95599200901215522', cash=4800}账户,当前金额为4800

posted @ 2012-12-31 12:04  Kyle_Java  阅读(277)  评论(0编辑  收藏  举报