Condition的使用

Condition用于实现条件锁,可以唤醒指定的阻塞线程。下面来实现一个多线程顺序打印a,b,c的例子。

先来看用wait和notify的实现:

public class Demo {

private volatile int singal;

public synchronized void a() {
        while (singal != 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("a");
        singal++;
        notifyAll();
    }

public synchronized void b() {
        while (singal != 1) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("b");
        singal++;
        notifyAll();
    }

public synchronized void c() {
        while (singal != 2) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("c");
        singal = 0;
        notifyAll();
    }

public static void main(String[] args) {
        Demo demo = new Demo();
        A a = new A(demo);
        B b = new B(demo);
        C c = new C(demo);

new Thread(a).start();
        new Thread(b).start();
        new Thread(c).start();
    }
}

class A implements Runnable {

private Demo demo;

public A(Demo demo) {
        this.demo = demo;
    }

@Override
    public void run() {
        while (true) {
            demo.a();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class B implements Runnable {

private Demo demo;

public B(Demo demo) {
        this.demo = demo;
    }

@Override
    public void run() {
        while (true) {
            demo.b();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class C implements Runnable {

private Demo demo;

public C(Demo demo) {
        this.demo = demo;
    }

@Override
    public void run() {
        while (true) {
            demo.c();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

再来看一下用Condition的实现,可以发现Condition实现更方便,可以实现指定条件的唤醒:

public class DemoCondition {

private volatile int singal;

private Lock lock = new ReentrantLock();

private Condition a = lock.newCondition();

private Condition b = lock.newCondition();

private Condition c = lock.newCondition();

public void a() {
        lock.lock();
        while (singal != 0) {
            try {
                a.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("a");
        singal++;
        b.signal();
        lock.unlock();
    }

public void b() {
        lock.lock();
        while (singal != 1) {
            try {
                b.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("b");
        c.signal();
        singal++;
        lock.unlock();
    }

public void c() {
        lock.lock();
        while (singal != 2) {
            try {
                c.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("c");
        a.signal();
        singal = 0;
        lock.unlock();
    }

public static void main(String[] args) {
        DemoCondition demo = new DemoCondition();
        A a = new A(demo);
        B b = new B(demo);
        C c = new C(demo);

new Thread(a).start();
        new Thread(b).start();
        new Thread(c).start();
    }
}

class A implements Runnable {

private DemoCondition demo;

public A(DemoCondition demo) {
        this.demo = demo;
    }

@Override
    public void run() {
        while (true) {
            demo.a();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class B implements Runnable {

private DemoCondition demo;

public B(DemoCondition demo) {
        this.demo = demo;
    }

@Override
    public void run() {
        while (true) {
            demo.b();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class C implements Runnable {

private DemoCondition demo;

public C(DemoCondition demo) {
        this.demo = demo;
    }

@Override
    public void run() {
        while (true) {
            demo.c();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

2.用Condition实现一个有界队列。

public class MyQueue<E> {

private Object[] obj;

// 添加操作下标
    private int addIndex;

// 删除操作下标
    private int removeIndex;

// 实际队列长度
    private int queueSize;

private Lock lock = new ReentrantLock();

private Condition add = lock.newCondition();

private Condition remove = lock.newCondition();

public MyQueue(int count) {
        this.obj = new Object[count];
    }

public void add(E e) {
        lock.lock();
        // 队列已满则等待
        while (queueSize == obj.length) {
            try {
                System.out.println(Thread.currentThread().getName() + " 队列已满,不能入队");
                add.await();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
        obj[addIndex++] = e;
        if (addIndex == obj.length - 1) {
            addIndex = 0;
        }
        queueSize++;
        System.out.println(Thread.currentThread().getName() + " 当前队列大小: " + queueSize);
        remove.signal();
        lock.unlock();
    }

public void remove() {
        lock.lock();
        // 队列已空则等待
        while (queueSize == 0) {
            try {
                System.out.println(Thread.currentThread().getName() + " 队列已空,无法出队");
                remove.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        obj[removeIndex] = null;
        if (++removeIndex == obj.length) {
            removeIndex = 0;
        }
        queueSize--;
        System.out.println(Thread.currentThread().getName() + " 当前队列长度: " + queueSize);
        add.signal();
        lock.unlock();
    }

public static void main(String[] args) {
        final MyQueue<Integer> myQueue = new MyQueue<>(4);

new Thread() {
            @Override
            public void run() {
                while (true) {
                    myQueue.add(1);
                }
            }
        }.start();

new Thread() {
            @Override
            public void run() {
                myQueue.remove();
            }
        }.start();
    }
}

参考资料:

《java并发编程实战》 龙果学院

Java并发编程原理与实战二十二:Condition的使用的更多相关文章

  1. Java并发编程原理与实战四十二:锁与volatile的内存语义

    锁与volatile的内存语义 1.锁的内存语义 2.volatile内存语义 3.synchronized内存语义 4.Lock与synchronized的区别 5.ReentrantLock源码实 ...

  2. Java并发编程原理与实战三十二:ForkJoin框架详解

    1.Fork/Join框架有什么用呢? ------->Fork使用来切分任务,Join是用来汇总结果.举个简单的栗子:任务是1+2+3+...+100这个任务(当然这个任务的结果有好的算法去做 ...

  3. Java并发编程原理与实战三十五:并发容器ConcurrentLinkedQueue原理与使用

    一.简介 一个基于链接节点的无界线程安全队列.此队列按照 FIFO(先进先出)原则对元素进行排序.队列的头部 是队列中时间最长的元素.队列的尾部 是队列中时间最短的元素.新的元素插入到队列的尾部,队列 ...

  4. Java并发编程原理与实战三十四:并发容器CopyOnWriteArrayList原理与使用

    1.ArrayList的实现原理是怎样的呢? ------>例如:ArrayList本质是实现了一个可变长度的数组. 假如这个数组的长度为10,调用add方法的时候,下标会移动到下一位,当移动到 ...

  5. Java并发编程原理与实战三十六:阻塞队列&消息队列

    一.阻塞队列 1.阻塞队列BlockingQueue ---->可以理解成生产者消费者的模式---->消费者要等待到生产者生产出来产品.---->而非阻塞队列ConcurrentLi ...

  6. Java并发编程原理与实战四十:JDK8新增LongAdder详解

    传统的原子锁AtomicLong/AtomicInt虽然也可以处理大量并发情况下的计数器,但是由于使用了自旋等待,当存在大量竞争时,会存在大量自旋等待,而导致CPU浪费,而有效计算很少,降低了计算效率 ...

  7. Java并发编程原理与实战四十五:问题定位总结

    背景   “线下没问题的”. “代码不可能有问题 是系统原因”.“能在线上远程debug么”    线上问题不同于开发期间的bug,与运行时环境.压力.并发情况.具体的业务相关.对于线上的问题利用线上 ...

  8. Java并发编程原理与实战四十四:final域的内存语义

    一.final域的重排序规则 对于final域,编译器和处理器要遵循两个重拍序规则: 1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 ...

  9. Java并发编程原理与实战三十八:多线程调度器(ScheduledThreadPoolExecutor)

    在前面介绍了java的多线程的基本原理信息:线程池的原理与使用 本文对这个java本身的线程池的调度器做一个简单扩展,如果还没读过上一篇文章,建议读一下,因为这是调度器的核心组件部分. 我们如果要用j ...

  10. Java并发编程原理与实战三十:CountDownLatch与CyclicBarrier 区别

    相信每个想深入了解多线程开发的Java开发者都会遇到CountDownLatch和CyclicBarrier,大家也在网上看到各种介绍原理,代码的,以及他们区别(应付面试)的,但是很少能讲清楚:他们到 ...

随机推荐

  1. 《TCP/IP 详解 卷1:协议》第 5 章:Internet 协议

    IP 是 TCPIP 协议族中的核心协议.所有 TCP.UDP.ICMP.IGMP 数据都通过 IP 数据包(又称为 packet)来传输.IP 的英文名为 Internet Protocol,是互联 ...

  2. 《软件工程和Python》第0周作业1

    写在前面的话 欢迎大家开始一段新的课程学习!从开博客开始吧.每次博客作业都会有评分,计入总成绩哦. 1.   截止日期 本次作业的提交截止时间:见老师要求 2.   作业要求 (1)建立个人技术博客和 ...

  3. 13_Java面向对象_第13天(static、final、匿名对象、内部类、包、修饰符、代码块)_讲义

    今日内容介绍 1.final 关键字 2.static 关键字 3.匿名对象 4.内部类 5.包的声明与访问 6.访问修饰符 7.代码块 01final关键字概念 A: 概述 继承的出现提高了代码的复 ...

  4. cxgrid中,如何根据列名或字段名取得footer值

    注意,不是根据index取得footer值cxgrdtbv1.DataController.Summary.FooterSummaryValues[0]; ------解决方案------------ ...

  5. HDU4726——Kia's Calculation——2013 ACM/ICPC Asia Regional Online —— Warmup2

    题目的意思是给你两个数字(多达10^6位) 做加法,但是有一点,没有进位(进位不算,相当于这一位相加后对10取模) 你可以任意排列两个数字中的每一位,但是不能是0开头. 现在题目要求以这种不进位的算法 ...

  6. codeforces 1041 E.Vasya and Good Sequences(暴力?)

    E. Vasya and Good Sequences time limit per test 2 seconds memory limit per test 256 megabytes input ...

  7. P4329 [COCI2006-2007#1] Bond

    题意翻译 有n 个人去执行n 个任务,每个人执行每个任务有不同的成功率,每个人只能执行一个任务,求所有任务都执行的总的成功率. 输入第一行,一个整数n (1≤n≤20 ),表示人数兼任务数.接下来n ...

  8. java的object类函数详解

    1.clone方法(浅拷贝) 保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常. 主要是JAVA里除了8种 ...

  9. Oracle 修改dmp的表空间

    1.百度下载  UltraEdit 并安装 2.打开程序,文件-->打开-->找到dmp  文件太大会提示,选择第一个默认,确定 3.按CTRL+H 转成十六进制编辑 4.例如:dmp里面 ...

  10. 【刷题】BZOJ 2154 Crash的数字表格

    Description 今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple).对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数.例如 ...