1. 程式人生 > >Java併發程式設計系列之十七 Condition介面

Java併發程式設計系列之十七 Condition介面

                     

通過前面的文章,我們知道任何一個Java物件,都擁有一組監視器方法,主要包括wait()、notify()、notifyAll()方法,這些方法與synchronized關鍵字配合使用可以實現等待/通知機制。而且前面我們已經使用這種方式實現了生產者-消費者模式。類似地,Condition介面也提供類似的Object的監視器的方法,主要包括await()、signal()、signalAll()方法,這些方法與Lock鎖配合使用也可以實現等待/通知機制。

相比Object實現的監視器方法,Condition介面的監視器方法具有一些Object所沒有的特性:

  1. Condition介面可以支援多個等待佇列,在前面已經提到一個Lock例項可以繫結多個Condition,所以自然可以支援多個等待隊列了
  2. Condition介面支援響應中斷,前面已經提到過
  3. Condition介面支援當前執行緒釋放鎖並進入等待狀態到將來的某個時間,也就是支援定時功能

使用Condition介面配合Lock鎖的使用例項如下:

    Lock lock = new ReentrantLock();    Condition condition = lock.newCondition();    public void conditionWait() throws InterruptedException {        lock.lock();        try {            //....            condition.await
();        }finally {            lock.unlock();        }    }    public void conditionSignal(){        lock.lock();        try {            //...            condition.signal();        }finally {            lock.unlock();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

一般而言,都會將Condition變數作為成員變數。當呼叫await方法後,當前執行緒會釋放鎖並進入Condition變數的等待佇列,而其他執行緒呼叫signal方法後,通知正在Condition變數等待佇列的執行緒從await方法返回,並且在返回前已經獲得了鎖

現在我們已經知道了如何配合Condition和Lock鎖實現等待/通知機制,那麼我們使用這種方式實現生產者-消費者模式:

package com.rhwayfun.concurrency.r0405;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/** * Created by rhwayfun on 16-4-5. */public class ConditionProducerConsumerDemo {    //日期格式器    private static DateFormat format = new SimpleDateFormat("HH:mm:ss");    static class Info{        //作者        private String author;        //標題        private String title;        //是否開始生產的標誌        private boolean produce = true;        //Lock鎖        private Lock lock = new ReentrantLock();        //Condition變數        private Condition condition = lock.newCondition();        public Info(){}        public Info(String author, String title) {            this.author = author;            this.title = title;        }        public String getAuthor() {            return author;        }        public void setAuthor(String author) {            this.author = author;        }        public String getTitle() {            return title;        }        public void setTitle(String title) {            this.title = title;        }        /**         * 生產者執行的生產方法         * @param author         * @param title         * @throws InterruptedException         */        public void set(String author,String title) throws InterruptedException {            lock.lock();            try {                //沒有開始生產就等待                while (!produce){                    condition.await();                }                //如果已經開始生產                this.setAuthor(author);                TimeUnit.SECONDS.sleep(1);                this.setTitle(title);                //表示已經停止了生產可以取資料了                produce = false;                //通知消費者                condition.signal();            }finally {                lock.unlock();            }        }        /**         * 消費者執行的消費方法         * @throws InterruptedException         */        public void get() throws InterruptedException {            lock.lockInterruptibly();            try {                //如果已經開始生產就等待                while (produce){                    condition.await();                }                //如果沒有在生產就就可以取資料                System.out.println(Thread.currentThread().getName() + ":" + this.getAuthor()                        + "=" + this.getTitle() + " at "                        + format.format(new Date()));                //表示我已經取了資料,生產者可以繼續生產                produce = true;                //通知生產者                condition.signal();            }finally {                lock.unlock();            }        }    }    static class Producer implements Runnable{        private Info info;        public Producer(Info info) {            this.info = info;        }        public void run() {            boolean flag = true;            for (int i = 0; i < 5; i++){                if (flag){                    try {                        info.set("authorA","titleA");                        System.out.println(Thread.currentThread().getName() + ":" + info.getAuthor() + "="                                + info.getTitle() + " at " + format.format(new Date()));                        TimeUnit.SECONDS.sleep(1);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    flag = false;                }else {                    try {                        info.set("authorB","titleB");                        System.out.println(Thread.currentThread().getName() + ":" + info.getAuthor() + "="                                + info.getTitle() + " at " + format.format(new Date()));                        TimeUnit.SECONDS.sleep(1);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    flag = true;                }            }        }    }    static class Consumer implements Runnable{        private Info info;        public Consumer(Info info) {            this.info = info;        }        public void run() {            for (int i = 0; i < 5; i++){                try {                    info.get();                    TimeUnit.SECONDS.sleep(1);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    public static void main(String[] args) throws InterruptedException {        Info info = new Info();        Thread producer = new Thread(new Producer(info),"Producer");        Thread consumer = new Thread(new Consumer(info),"Consumer");        producer.start();        TimeUnit.SECONDS.sleep(1);        consumer.start();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173

執行結果如下:

這裡寫圖片描述

與使用Object的監視器方法達到了同樣的效果,也許看不出Condition配合Lock鎖的優勢何在。但是在複雜多執行緒的程式設計中,這種方式可以體現出其優勢。所以一般使用的時候仍然是Object的監視器方法居多。