iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 2
0
自我挑戰組

學習筆記系列 第 5

Java Producer Consumer pattern

  • 分享至 

  • xImage
  •  

記錄學習內容。
主要是看網路上的文章和影片,做些紀錄。
大部分內容來自網路上大大的文章

Java Producer Consumer pattern

之前有關執行緒的:
Android ,存圖片到SQLite,process、thread、ByteArrayOutputStream

來了解生產者與消費者:
Java Concurrency Interview: Implement Producer Consumer pattern using wait-notify

producer(生產者):生產食物。
如果 倉庫是滿的 ,就要等待到 顧客發信號(代表:顧客吃了一些東西,所以現在倉庫有空位了),之後繼續生產

Consumer (消费者):吃東西。
如果 倉庫是空的 ,就要等待到 producer(生產者)發出信號(代表: 生產者現在有生產食物了) ,之後繼續吃

把教學影片的程式,照打練習:
第一段用BlockingQueue的方式:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ThreadTest5 {

    static class Ipad {

    }

    /*static void ConsumerPlayIpad(Ipad ipad) {
        System.out.println(" ConsumerPlayIpad: " +  ipad.toString() );
    }*/

    public static void main(String[] args) throws InterruptedException {

        BlockingQueue<Ipad> queue = new ArrayBlockingQueue<>(10);

        //producer
        final Runnable producer = () -> {
            while (true) {
                try {
                    Ipad i = new Ipad();
                    queue.put(i);
                    System.out.println(" ProducerReleaseIpad ");
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        new Thread(producer).start();
        new Thread(producer).start();

        //consumer
        final Runnable consumer = () -> {
            while (true) {
                try {
                    Ipad i = queue.take();
                    System.out.println(" ConsumerPlayIpad: " + i.toString());
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        };
        new Thread(consumer).start();
        new Thread(consumer).start();

    }

}

結果:
https://ithelp.ithome.com.tw/upload/images/20200902/201119949RqixSe1Hz.png

第二段改成 DIY BlockingQueue :
這邊講到 如果 生產者 只生產 一個東西 ,但是 在等待的消费者有兩個 。
這時候 會不會造成 有一個消費者 吃不到東西 , 所以從if判斷 改成while判斷 ,這樣notEmpty.await();之後 ,就會在跑一次迴圈 ,檢查queue.size() == 0 。

如果用if會發生這個錯誤:
https://ithelp.ithome.com.tw/upload/images/20200902/20111994EyaeEOHz8i.png

程式:

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadTest6 {

    static class MyBlockingQueue<E> {

        private Queue<E> queue;
        private int max = 16;
        private ReentrantLock lock = new ReentrantLock(true);
        private Condition notEmpty = lock.newCondition();
        private Condition notFull = lock.newCondition();

        public MyBlockingQueue(int size) {
            queue = new LinkedList<>();
            this.max = size;
        }

        public void put(E e) {
            lock.lock();
            try {
                while (queue.size() == max) {
                    notFull.await();
                }
                queue.add(e);
                Thread.sleep(3000);
                System.out.println(" ProducerReleaseIpad ");
                notEmpty.signalAll();
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public E take() {
            lock.lock();
            E item = null;
            try {
                while (queue.size() == 0) {
                    notEmpty.await();
                }
                item = queue.remove();
                Thread.sleep(3000);
                System.out.println(" ConsumerPlayIpad: " + item.toString());
                notFull.signalAll();

            } catch (InterruptedException e1) {
                e1.printStackTrace();
            } finally {
                lock.unlock();
            }
            return item;
        }

    }

    static class Ipad {

    }


    public static void main(String[] args) throws InterruptedException {

        MyBlockingQueue<Ipad> myBlockingQueue = new MyBlockingQueue<Ipad>(5);

        //consumer
        final Runnable consumer = () -> {
            while (true) {
                Ipad i = myBlockingQueue.take();
            }
        };
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
        //producer
        final Runnable producer = () -> {
            while (true) {
                Ipad i = new Ipad();
                myBlockingQueue.put(i);
            }
        };

        new Thread(producer).start();
        new Thread(producer).start();

    }


}


結果:
https://ithelp.ithome.com.tw/upload/images/20200902/20111994Yidfhp6tjP.png

第三段:
lock 換成 synchronized 。
await() 和signalAll() 換成 wait() 和notifyAll()

目前測試失敗,會有這個錯誤,還不會改:
https://ithelp.ithome.com.tw/upload/images/20200902/20111994SCx3cW681y.png

wait() 和notifyAll()參考:
Day 28 介紹 Producer Consumer 模式


上一篇
HTTP、Get、Post
下一篇
Ruby on Rails ,LINE Bot 學習筆記
系列文
學習筆記46
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言