zoukankan      html  css  js  c++  java
  • java ReentrantLock Condition

    sychronized、wait、notify、notifyAll、sleep

    在多线程环境下,为了防止多个线程同时调用同一个方法、修改同一份变量,造成数据读取结果混乱,可以使用synchronized关键字,对一个方法或者代码块实现同步调用,即只能一个线程调用完此方法后,下一个线程才能调用此方法。

    当synchronized修饰的是一个类方法时,使用的是此的Monitor实现同步(锁)。

    当synchronized修饰的是一个实例方法时,使用的是此实例的Monitor实现同步(锁)。

    当synchronized修饰的是一个代码块时,使用的是括号中变量的Monitor实现同步(锁)。

    在StringBuffer、Hashtable、Vector等类中,为了实现方法同步,大量使用了sychronized关键字修饰方法。

    当sychronized修饰的方法或者代码块,执行sleep时,进入time_waiting阶段,并会继续持有锁,直到sleep结束,或者被interrupted,继续执行,直到释放锁。

    当sychronized修饰的方法或者代码块,执行wait时,进入waiting阶段,并释放持有的锁,当收到notify通知,或者被interrupted后,会重新竞争获取到锁,才会继续运行。注意,此时虽然处于同步方法中,但其在wait时锁被释放了,只有重新竞争获得锁,才能继续运行。

    在sychronized修饰的方法或者代码块中,如果执行notify,会唤醒一个waiting(同一个对象锁)中的线程进入runnable阶段,等到退出sychronized区域,waiting的线程获得锁继续执行进入running阶段;如果执行notifyAll方法,会唤醒所有waiting(同一个对象锁)中的线程,等到当前线程退出sychronized区域,所有waiting的线程竞争锁,未竞争获得锁的线程再次进入waiting阶段,等待唤醒。

    ReentrantLock、Condition

    使用ReentrantLock类实例化一个lock实例,并可以通过lock实例新建一个Condition实例。

    使用时,先用lock实例的lock方法,获得锁,在获得锁的期间可以使用此lock的Condition实例,进行await、signal、singalAll方法,发送信号,进行线程间通信。

    举一个阻塞队列的例子:

    通过lock对象,新建了两个Condition:notEmpty、notFull。

    执行add操作时,会检查list的元素个数是否达到最大值,达到时,等待notFull信号。

    执行take操作时,会检查list的元素个数是否为0,为0时,等待notEmpty信号。

    add执行成功时,会发送notEmpty信号,通知执行take的线程,等到add操作的lock执行unlock后,去获取数据。

    take执行成功时,会发送notFull信号,通知执行add的线程,等到take操作的lock执行unlock后,在去添加数据。

    注意:在Conditon发送各种信号之前,创建他们的lock必须执行lock()操作,获取锁;在Conditon发送各种信号之后,创建他们的lock必须执行unlock()操作,释放锁。

    class MyQueue {
        private ReentrantLock lock = new ReentrantLock();
        private Condition notEmpty = lock.newCondition();
        private Condition notFull = lock.newCondition();
        private AtomicInteger count = new AtomicInteger(0);
        private List<String> list = new LinkedList<String>();
        private final int MaxCount = 10;
    
        public void add(String str) {
            lock.lock();
            try {
                while (count.get() > MaxCount) {
                    notFull.await();
                }
                list.add(str);
                count.incrementAndGet();
                notEmpty.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public String take() {
            String retStr = null;
            lock.lock();
            try {
                while (count.get() == 0) {
                    notEmpty.await();
                }
                retStr = list.remove(0);
                count.decrementAndGet();
                notFull.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return retStr;
        }
    }
  • 相关阅读:
    Linux的进程线程及调度
    Linux-485收发切换延迟的解决方法
    FFmpeg内存IO模式(内存区作输入或输出)
    ffplay源码分析7-播放控制
    ffplay源码分析6-音频重采样
    ffplay源码分析5-图像格式转换
    ffplay源码分析4-音视频同步
    ffplay源码分析3-代码框架
    ffplay源码分析2-数据结构
    ffplay源码分析1-概述
  • 原文地址:https://www.cnblogs.com/mahuan2/p/6606978.html
Copyright © 2011-2022 走看看