Java Concurrency Condition Interface

Through the previous article, we know that any Java object has a set of monitor methods, mainly including wait(), notify(), notifyAll() methods, which can be used in conjunction with the synchronized keyword to implement a wait/notification mechanism. And we have already implemented the producer-consumer pattern in this way. Similarly, the Condition interface also provides similar methods of Object monitors, mainly including await(), signal(), and signalAll() methods. These methods can also be used in conjunction with the Lock lock to implement the wait/notification mechanism.

Compared with the monitor method implemented by Object, the monitor method of the Condition interface has some features that Object does not have:

  1. The Condition interface can support multiple waiting queues. As mentioned earlier, a Lock instance can bind multiple conditions, so it can naturally support multiple waiting queues.
  2. The Condition interface supports responding to interrupts, as mentioned earlier
  3. The Condition interface supports the current thread to release the lock and enter the waiting state to a certain time in the future, that is, to support the timing function

An example of using the Condition interface with the Lock lock is as follows:

    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();
        }
    }

Generally speaking, the Condition variable is used as a member variable. When the await method is called, the current thread will release the lock and enter the waiting queue of the Condition variable. After other threads call the signal method, they will notify the thread waiting for the Condition variable to return from the await method and have acquired the lock before returning .

Now that we know how to implement the waiting/notification mechanism with Condition and Lock locks, we implement the producer-consumer pattern in this way:

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();
    }
}

The results are as follows:

write picture description here

It achieves the same effect as the use of Object's monitor method, and it may not be clear what the advantage of Condition with Lock is. But in complex multi-threaded programming, this method can reflect its advantages. Therefore, in general use, it is still mostly the monitor method of Object.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325363518&siteId=291194637