• 【转】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

  • 相关阅读:
    asp.net 文件下载
    net 数据库连接详解 相当经典啊
    取值:webconfig中的key
    通过监听的端口查找本机进程和服务思路
    以系统服务运行某个程序
    测底根除Windows流氓软件开机自动运行
    使用Wireshark在主机上抓取远程主机的数据流量
    记录Windows远程登录日志
    证书不匹配发出告警的解决方法
    WPS office云同步图标彻底删除方法
  • 原文地址:https://www.cnblogs.com/xuekyo/p/2840444.html
Copyright © 2020-2023  润新知