zoukankan      html  css  js  c++  java
  • Java并发编程实战 第14章 构建自定义的同步工具

    状态依赖性

    定义:只有满足特定的状态才能继续执行某些操作(这些操作依赖于固定的状态,这些状态需要等待别的线程来满足)。

    FutureTask,Semaphroe,BlockingQueue等,都是状态依赖性的类。

    条件队列

    条件对列:条件对列就是由于不满足继续的条件而被wait操作阻塞的线程队列。他们都在等待条件满足,然后被唤醒。

    条件谓词:状态依赖性依赖的前提条件。如BlockingQueue中的isFull,isEmpty等。

    条件等待中存在三个要素:加锁 + 条件谓词 + wait方法

    wait方法和notify方法

    我理解的wait方法:会释放锁+阻塞当前线程,放入条件对列,等待被唤醒,唤醒后,需要重新获得锁,获得锁之后继续执行wait那句代码所在的位置(即使wait在锁块的中间代码部分)。

    notify(All)方法:只是唤醒条件队列中的线程。但是不释放锁。

    使用wait notify方法的时候,一定要持有条件对列所属的锁。

    使用轮询和休眠实现简单的状态依赖性阻塞

    1. while(true)
    2.         {
    3.             //这里不对循环上锁,不然这个锁就无法释放了,不对休眠上锁,休眠上锁,在休眠的时候别人也无法操作,永远都不可能有元素出去
    4.             synchronized (this)
    5.             {
    6.                 //如果队列不是满的,那么就放入元素
    7.                 if(!this.isFull())
    8.                 {
    9.                     this.doPut(v);
    10.                     return;
    11.                 }
    12.             }
    13.             //否则休眠,退出cpu占用
    14.             Thread.sleep(SLEEP_GRANULARITY);
    15.         }
    16.     }

    使用条件队列来实现状态依赖性阻塞

    1. public synchronized void put(V v) throws InterruptedException
    2.    {
    3.        while(this.isFull())
    4.        {
    5.            //这里挂起程序,会释放锁
    6.            this.wait();
    7.        }
    8.        //如果队列不为满的,那么程序被唤醒之后从新获取锁
    9.        this.doPut(v);
    10.        //执行结束,唤醒其他队列
    11.        this.notifyAll();
    12.    }

    注意上面要使用while。

    对于监视器来说,wait操作产生的线程,都放在这个监视器唯一的条件队列里。

    如果使用Lock,可以使用condition来产生不同的条件对列。

    注意上面的 this.notifyAll();代码,将会唤醒这个监视器条件队列里所有等待的线程。其实这里只用唤醒因为empty阻塞的线程,而不用唤醒因为full阻塞的线程。

    如果使用 this.notify(),只会随机唤醒一个,如果唤醒的是因为full堵塞的线程,那么就可能没有正常唤醒。影响性能,甚至造成活跃性的危险。

    这种情况下,可以使用Lock和Condition来改造。

    1. protected final Lock lock = new ReentrantLock();
    2. private final Condition notFull = lock.newCondition();
    3. private final Condition notEmpty = lock.newCondition();
    4.  
    5.  public void put(T x) throws InterruptedException {
    6.         lock.lock();
    7.         try {
    8.             while (count == items.length)
    9.                 notFull.await();
    10.             items[tail] = x;
    11.             if (++tail == items.length)
    12.                 tail = 0;
    13.             ++count;
    14.             notEmpty.signal();
    15.         } finally {
    16.             lock.unlock();
    17.         }
    18.     }

    注意:这里不是signalAll。

    阀门类

    使用闭锁CountDownLatch,传入1的时候可以作为阀门开关。前提是在其他线程的第一步先执行开关的await。使用开关的countDown方法就可以打开开关。

    但是这种阀门,只能打开,不能关闭。

    使用wait和notifyAll来实现可重新关闭的阀门。

    Condition

    注意,由于Condition对象继承自Object,它也有wait,notify,notifyAll方法,其实它对应方法名字应该是await,signal,signalAll。

  • 相关阅读:
    vue-cli中安装方法
    css初始化
    VUE基本指令(v-model,v-html,v-text,v-bind,v-if,v-show,v-for,v-on:click,组件,过滤器)
    在浏览器上安装 Vue Devtools工具
    vue前端框架面试问题汇总
    git修改用户名、邮箱
    js对字符串的一些操作方法
    11款JavaScript颜色拾取插件推荐
    vue-devtools的安装与使用
    JS里的居民们4-数组((堆)队列
  • 原文地址:https://www.cnblogs.com/xiaolang8762400/p/7074721.html
Copyright © 2011-2022 走看看