Condition 的使用

Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。Condition的使用必须是在lock修饰的语句块中。
下面给出一个简单的示例:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by litao on 15/5/26.
 */
public class TaskTest {

    private boolean flag;
    private int num;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void sub() {
        lock.lock();
        while (flag == false) {
            try {
                condition.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        for (int i = 0; i < 5; i++) {
            num--;
            System.out.println("sub num:" + num);
        }
        flag = false;
        condition.signal();
        lock.unlock();
    }

    public void add() {
        lock.lock();
        while (flag == true) {
            try {
                condition.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        for (int i = 0; i < 5; i++) {
            num++;
            System.out.println("add num:" + num);
        }
        flag = true;
        condition.signal();
        lock.unlock();
    }

    public static void main(String[] args) {

        final TaskTest taskTest = new TaskTest();
        Thread thread1 = new Thread() {
            @Override
            public void run() {
                taskTest.sub();
            }
        };
        Thread thread2 = new Thread() {
            @Override
            public void run() {
                taskTest.add();
            }
        };
        thread1.start();
        thread2.start();
    }
}

执行结果:
add num:1
add num:2
add num:3
add num:4
add num:5
sub num:4
sub num:3
sub num:2
sub num:1
sub num:0
可以看出,condition.signal()和condition.await()在这种情况下和传统的notify,wait具有相同的功效。

既然condition提供的功能和传统的方法相同,那为啥还要有这个东东呢?下面介绍condition的独特的地方。

public class Buffer {
    private Lock lock = new ReentrantLock();
    private Condition readCondition = lock.newCondition();
    private Condition writeCondition = lock.newCondition();
    private LinkedList<String> buffers;
    private int size = 0;
    private int maxSize;

    public Buffer(int maxSize) {
        this.maxSize = maxSize;
        buffers=new LinkedList<String>();
    }

    public String get() {
        lock.lock();
        while (size == 0) {
            try {
                readCondition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        String tmp = buffers.poll();
        size = size - 1;
        System.out.println(Thread.currentThread().getName()+" ,get: "+tmp);
        writeCondition.signalAll();
        lock.unlock();
        return tmp;
    }

    public void set(String str) {
        lock.lock();
        while (size == maxSize) {
            try {
                writeCondition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        buffers.offer(str);
        size = size + 1;
        System.out.println(Thread.currentThread().getName()+" ,set: "+str);
        readCondition.signalAll();
        lock.unlock();
    }
}

上面代码使一个使用了Condition实现的的Buffer。
这里将写和读分别使用了writeCondition和readCondition,相较于传统的notify,主要的区别是:使用condition可以按条件唤醒不同的线程,当可读的时候只唤醒读线程,当可写的时候只唤醒写线程。这样,不会致使某个无关的线程被唤醒后,立即又被阻塞。可以提高程序的执行效率。
使用上面Buffer,实现的一个生产者-消费者模型

import java.util.Random;

/**
 * Created by litao on 15/5/26.
 * 生产者-消费者模型
 */
public class ProducerAndConsumer {

    public static void main(String[] args) {

        final String[] randomStr = {
                "0asaswwdwdwdw",
                "1aswswswdwdwdw",
                "2asasaswwdwd",
                "3asaswwdwd",
                "4sdsdwwdwd"
        };
        final Buffer buffer = new Buffer(5);

        final Producer producer = new Producer(buffer);
        final Consumer consumer = new Consumer(buffer);
        final Random random = new Random();
        for (int i = 0; i < 10; i++) {
            Thread thread1 = new Thread("producer" + i) {
                @Override
                public void run() {
                    int index = random.nextInt(5);
                    producer.produce(randomStr[index]);
                }
            };
            thread1.start();
        }

        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread("consumer" + i) {
                @Override
                public void run() {
                    String str = consumer.consum();
                    System.out.println("str:" + str);
                }
            };
            thread.start();
        }

    }
    public static class Producer {
        private Buffer buffer;

        public Producer(Buffer buffer) {
            this.buffer = buffer;
        }

        public void produce(String str) {
            buffer.set(str);
        }
    }

    public static class Consumer {
        private Buffer buffer;

        public Consumer(Buffer buffer) {
            this.buffer = buffer;
        }

        public String consum() {
            return buffer.get();
        }
    }
}

程序执行结果:
producer0 ,set: 0asaswwdwdwdw
producer1 ,set: 0asaswwdwdwdw
producer2 ,set: 0asaswwdwdwdw
producer3 ,set: 3asaswwdwd
producer4 ,set: 2asasaswwdwd
consumer0 ,get: 0asaswwdwdwdw
producer5 ,set: 4sdsdwwdwd
str:0asaswwdwdwdw
consumer1 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw
producer6 ,set: 0asaswwdwdwdw
consumer4 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw
producer8 ,set: 1aswswswdwdwdw
consumer5 ,get: 3asaswwdwd
str:3asaswwdwd
producer9 ,set: 4sdsdwwdwd
consumer2 ,get: 2asasaswwdwd
str:2asasaswwdwd
consumer3 ,get: 4sdsdwwdwd
str:4sdsdwwdwd
producer7 ,set: 0asaswwdwdwdw
consumer6 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw
consumer7 ,get: 1aswswswdwdwdw
str:1aswswswdwdwdw
consumer8 ,get: 4sdsdwwdwd
str:4sdsdwwdwd
consumer9 ,get: 0asaswwdwdwdw
str:0asaswwdwdwdw

posted @ 2015-10-12 10:30  黎明露珠  阅读(451)  评论(0编辑  收藏  举报