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并发编程原理与实战三十四:并发容器CopyOnWriteArrayList原理与使用


下一篇:Linux下安装Apache并以mod_wsgi方式部署django站点