Java并发编程原理与实战二十二:Condition的使用

Posted 屌丝码农

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java并发编程原理与实战二十二:Condition的使用相关的知识,希望对你有一定的参考价值。

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的使用的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程原理与实战二十四:简易数据库连接池

Java并发编程原理与实战二十九:Exchanger

Java并发编程原理与实战二十六:闭锁 CountDownLatch

Java并发编程原理与实战二十五:ThreadLocal线程局部变量的使用和原理

Java并发编程原理与实战二十:线程安全性问题简单总结

Java并发编程原理与实战二十一:线程通信wait&notify&join