zoukankan      html  css  js  c++  java
  • Java提高——JUC锁02-互斥锁ReentrantLock

    ReentrantLocak

    ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”。

    ReentrantLock锁在同一个时间点只能被一个线程持有;而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取

    ReentrantLock分为“公平锁”和“非公平锁”。他们最大的区别体现在获取锁的机制上是否公平。“锁”是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock在同一个时间点只能被一个线程获取(当某线程获取到“锁”时,其他线程就必须等待);ReentrantLock是通过一个FIFO的等待队列来管理获取该锁的所有线程的。在“公平锁”的机制下,线程一次排队获取;而“非公平锁”在锁是可获取状态的时候,不管自己是不是在队列开头都会获取锁。

    ReentrantLock的函数列表

    /**
     * 创建一个ReentrantLock,默认是“非公平锁”
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    
    /**
     * 创建策略是faire的ReentrantLock。fair为true表示是公平锁,为false表示为非公平锁
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    
    /**
     * 获取锁
     */
    public void lock() {
        sync.lock();
    }
    
    /**
     * 如果当前线程未被中断则获取锁
     */
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    
    /**
     * 仅在调用时,锁未被另一个线程保持的状况下才获取锁
     */
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    
    /**
     * 如果锁在给定的时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁
     */
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
    
    /**
     * 视图释放此锁
     */
    public void unlock() {
        sync.release(1);
    }
    
    /**
     * 返回与此Lock实例一起使用的Condition实例
     */
    public Condition newCondition() {
        return sync.newCondition();
    }
    
    /**
     * 查询当前线程保持此锁的次数
     */
    public int getHoldCount() {
        return sync.getHoldCount();
    }
    
    /**
     * 该锁是否被当前线程保持
     */
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
    
    /**
     * 查询此锁是否由任意线程保持
     */
    public boolean isLocked() {
        return sync.isLocked();
    }
    
    /**
     * 判断是否是公平锁
     */
    public final boolean isFair() {
        return sync instanceof FairSync;
    }
    
    /**
     * 返回目前拥有此锁的线程
     */
    protected Thread getOwner() {
        return sync.getOwner();
    }
    
    /**
     * 查询是否有些线程正在等待获取此锁
     */
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
    
    /**
     * 查询给定线程是否正在等待获取此锁
     */
    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }
    
    /**
     * 返回正在等待获取此锁的线程估计数
     */
    public final int getQueueLength() {
        return sync.getQueueLength();
    }
    
    /**
     * 返回包含可能正在等待的线程的集合
     *
     * @return the collection of threads
     */
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }
    
    /**
     * 查询是否有线程正在等待
     */
    public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
    }
    
    /**
     * 返回等待与此锁相关的给定条件的线程估计数
     */
    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    实例:认识lock和unlock

    第一版:

    class Depot{
        private Integer size;//仓库的实际数量
        private Lock lock;//独占锁
    
        public Depot() {
            this.size = 0;
            this.lock = new ReentrantLock();
        }
    
        public void produce(int val){
            lock.lock();//加锁
            try {
                size += val;
                System.out.println(Thread.currentThread().getName()+","+val +","+size);
            } finally {
                lock.unlock();//释放锁
            }
        }
    
        public void consume(int val){
            lock.lock();
            try {
                size -= val;
                System.out.println(Thread.currentThread().getName()+","+val +","+size);
            } finally {
                lock.unlock();
            }
        }
    }
    class producer{
        private Depot depot;
    
        public producer(Depot depot) {
            this.depot = depot;
        }
    
        //新建一个线程向仓库中生产产品
        public void produce(int val){
            new Thread(){
                @Override
                public void run(){
                    depot.produce(val);
                }
            }.start();
        }
    }
    class cunsumer{
        private Depot depot;
    
        public cunsumer(Depot depot) {
            this.depot = depot;
        }
        //新建一个线程向仓库中生产产品
        public void consume(final int val){
            new Thread(){
                @Override
                public void run(){
                    depot.consume(val);
                }
            }.start();
        }
    }
    
    public class TestLock {
        public static void main(String[] args) {
            Depot depot = new Depot();
            producer p = new producer(depot);
            cunsumer c = new cunsumer(depot);
    
            p.produce(60);
            p.produce(120);
            c.consume(90);
            c.consume(150);
            p.produce(110);
        }
    }


    1)Depot仓库通过produce向其中生产货物,通过consume消耗仓库中的货物。通过独占锁lock实现仓库的互斥访问:在操作仓库中的货物前会通过lock锁住仓库,操作完成之后通过unlock解锁。

    2)producer通过调用produce方法新建一个线程向仓库中生产货物

    3)consumer通过consume方法通过新建一个线程消耗仓库中的货物

    4)主线程main中建一个消费者和生产者,分别用于生产和消耗。最终剩余50.

    该模型中会有仓库为负和容量无限制的问题

    第二版:解决上面两个问题,通过Condition来解决,通过Condition的await( )方法,让线程阻塞(类似于wait());通过signal( )方法让线程唤醒(类似于notify())。

    class Depot{
        private Integer capacity;//仓库的容量
        private Integer size;//仓库的实际数量
        private Lock lock;//独占锁
        private Condition fullCondition;//生产条件
        private Condition emptyCondition;//消耗的条件
    
        public Depot(Integer capacity) {
            this.capacity = capacity;
            this.size = 0;
            this.lock = new ReentrantLock();
            this.fullCondition = lock.newCondition();
            this.emptyCondition = lock.newCondition();
        }
    
        public void produce(int val){
            lock.lock();//加锁
            try {
                //wantProduceVal表示想要生产的数量(可能量太多需要多次生产)
                int wantProduceVal=val;
    
                while (wantProduceVal>0){
                    //实际数量大于等于容量,库满,等待
                    while (size>=capacity){
                        fullCondition.await();
                    }
                        //获取实际生产的量,(即库存中新增的量)
                        //如果 库存+想要生产的量>库容量,则 实际的增量=库容量-库存,
                        //否则,实际增量=想要生产的量
                        int inc = (size+wantProduceVal)>capacity?(capacity-size):wantProduceVal;
                        size+=inc;
                        wantProduceVal-=inc;
                        //size += val;
                        System.out.println(Thread.currentThread().getName()+","+val +","+size);
    
                        //通知消费者消费
                        emptyCondition.signal();
                }
    
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();//释放锁
            }
        }
    
        public void consume(int val){
            lock.lock();
            try {
                //表示想要消耗的量(可能量太大)
                int wantConsumeVal = val;
                //没有库存则等待生产
                while (size<0) {
                    emptyCondition.await();
                }
                    //获取实际消耗的量(即库存中实际减少的量)
                    //如果 存库<要消耗的量,那么消耗量等于库存
                    //否则,减少的量就是要消耗的量
                    int dec = (wantConsumeVal>size)?size:wantConsumeVal;
                    size-=dec;
                    wantConsumeVal-=dec;
                    //size -= val;
                    System.out.println(Thread.currentThread().getName()+","+val +","+size);
    
                    //通知生产者生产
                    fullCondition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
    class producer{
        private Depot depot;
    
        public producer(Depot depot) {
            this.depot = depot;
        }
    
        //新建一个线程向仓库中生产产品
        public void produce(int val){
            new Thread(){
                @Override
                public void run(){
                    depot.produce(val);
                }
            }.start();
        }
    }
    class cunsumer{
        private Depot depot;
    
        public cunsumer(Depot depot) {
            this.depot = depot;
        }
        //新建一个线程向仓库中生产产品
        public void consume(final int val){
            new Thread(){
                @Override
                public void run(){
                    depot.consume(val);
                }
            }.start();
        }
    }
    
    public class TestLock {
        public static void main(String[] args) {
            Depot depot = new Depot(100);
            producer p = new producer(depot);
            cunsumer c = new cunsumer(depot);
    
            p.produce(60);
            p.produce(120);
            c.consume(90);
            c.consume(150);
            p.produce(110);
        }
    }
    


    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3496147.html

  • 相关阅读:
    Django CBV和FBV
    ArcGIS案例学习笔记2_1_山顶点提取最大值提取
    ArcGIS案例学习笔记2_1_学校选址适宜性分析
    ArcGIS案例学习笔记_3_2_CAD数据导入建库
    ArcGIS案例学习笔记3_1_地理配准案例_目视找点
    ArcGIS案例学习笔记3_1_地理配准案例_图面控制点
    ArcGIS案例学习笔记3_1_ArcMap编辑练习
    ArcGIS案例学习笔记4_2_城乡规划容积率计算和建筑景观三维动画
    ArcGIS案例学习笔记4_2_水文分析批处理地理建模
    ArcGIS案例学习笔记4_1_矢量校正
  • 原文地址:https://www.cnblogs.com/huangzhe1515023110/p/9276045.html
Copyright © 2011-2022 走看看