java, جاوا, حل مسائل با جاوا, همزمانی در جاوا (MultiThreading)

مسئله تولید کننده و مصرف کننده در جاوا (producer consumer)

مسئله تولید کننده و مصرف کننده در جاوا

در این جلسه تیم کدگیت را با آموزش مسئله تولید کننده و مصرف کننده در جاوا همراهی کنید.پیش نیاز این آموزش آشنایی با inner class و thread است. در این آموزش اگر با inner class آشنایی ندارید مشکلی ندارد و درون آموزش متوجه خواهید شد. پیش نیاز اصلی این آموزش آشنایی با سمافور است که در آموزش گذشته به طور کامل توضیح داده شده است.

مسئله تولید کننده و مصرف کننده

مسئله تولیدکننده-مصرف‌کننده (Producer–consumer problem ) یا مسئله بافر محدود (bounded-buffer problem ) مسئله‌ای کلاسیک در همگام‌سازی چندپروسه‌ای است که این پروسه‌ها یک ناحیه بحرانی مشترک (Critical Section ) دارند.

در این مسئله، دو فرایند به نام‌های تولیدکننده و مصرف‌کننده وجود دارد که یک بافر با اندازه‌ای ثابت در بین آنها به اشتراک گذاشته شده و آنها از این بافر به عنوان صف استفاده می‌کنند. وظیفه تولیدکننده این است که یک قلم داده تولید کرده و در بافر قرار دهد. به شکل همزمان، مصرف‌کننده باید این قلم داده را از بافر بردارد و آن را به مصرف برساند. تولیدکننده و مصرف‌کننده تنها می‌توانند هر بار یک قلم داده را در بافر قرار دهند یا از بافر بردارند. مسئله اینجاست که ما باید مطمئن شویم که تولیدکننده سعی نمی‌کند در یک بافر پر شده، داده‌ای را ذخیره کند و یا به طور مشابه، مصرف‌کننده سعی نکند داده‌ای را از یک بافر خالی بردارد. هرگاه که بافر پر بود و تولیدکننده خواست چیزی را در آن ذخیره کند، باید به خواب برود تا اینکه مصرف‌کننده یک قلم داده را از بافر بردارد و بعد از آن تولیدکننده را از خواب بیدار کند. به طور مشابه، اگر مصرف‌کننده خواست یک قلم داده را از یک بافر خالی بردارد، باید به خواب برود تا تولیدکنده یک قلم داده را در بافر قرار دهد و سپس مصرف‌کننده را بیدار کند. یک راه حل نامناسب برای این مسئله، می‌تواند به بن‌بست منجر شود که در آن هر دو پروسه همزمان به خواب می‌روند و هیچکس نیست تا آنها را از خواب بیدار کند که باید جلوی این اتفاق را گرفت. این مسئله را می‌توان به n تولیدکننده و m مصرف‌کننده تعمیم داد(ویکیپدیا).

ما در این آموزش فرض میکنیم که بافر نامحدود است(برای سادگی کار) و آموزش بعدی به پیاده سازی بافر محدود میپردازیم.

پیاده سازی مسئله تولید کننده و مصرف کننده در جاوا

برای پیاده سازی مسئله تولید کننده و مصرف کننده با بافر نامحدود از یک arraylist استفاده میکنیم که نقش بافر را دارد. ما هر بار عددی بین 0 تا 1 را در آن قرار میدهیم و به طور همزمان نیز از آن عدد استفاده میکنیم.

برای پیاده سازی تولید کننده ما یک کلاس درونی (inner class) برای خود نوشتیم به نام producer و دقیقا همین کار را برای مصرف کننده انجام دادیم ولی نام کلاس consumer هست. هر دو کلاس نوعی از runnable هستند.در آخر برای اجرای thread ها یک متد به نام buildthreads نوشتیم.برای تست برنامه ما buildthreads را صدا زدیم.

import java.util.ArrayList;



public class TestProducerConsumer {



     ArrayList<Double> buffer = new ArrayList<>();



     Semaphore mutex = new Semaphore(1);



     public static void main(String[] args) {

          new TestProducerConsumer().buildthreads();

     }



     public void buildthreads() {

          Thread producer = new Thread(new Producer());

          Thread consumer = new Thread(new Consumer());



          producer.start();

          consumer.start();



     }



     class Producer implements Runnable {



          @Override

          public void run() {

              while (true) {

                   produce();

              }



          }



          private void produce() {

              mutex.acquire();

              double number = Math.random();



              buffer.add(number);

              System.out.println("add to buffer " + number

                        + " and buffer size is " + buffer.size());

              mutex.release();



          }



     }



     class Consumer implements Runnable {



          @Override

          public void run() {

              while (true) {

                   consumer();

              }



          }



          private void consumer() {

              mutex.acquire();



              if (buffer.size() > 0) {

                   double number = buffer.remove(0);

                   System.out.println("removed from buffer " + number

                             + " and buffer size is " + buffer.size());

              }



              mutex.release();

          }



     }



}



public class Semaphore {

     private int value;



     public Semaphore(int value) {

          this.value = value;

     }



     public synchronized void acquire() {

          while (value <= 0) {

              try {

                   wait();

              } catch (InterruptedException e) {

              }

          }



          value--;

     }



     public synchronized void release() {

          ++value;



          notify();

     }

}

در کد مسئله تولید کننده و مصرف کننده در جاوا  از فیلد های زیر استفاده میشود:

  1. Buffer : این فیلد همان بافر نامحدود ماست.
  2. Mutex: این هم سمافوری برای ناحیه بحرانی ما است. چک میکند چند درخواست همزمان وارد ناحیه بحرانی ما نشود.

کد مسئله تولید کننده و مصرف کننده در جاوا شامل متدهای زیر است:

  1. Produce: شامل کد تولید کننده است و عددی را به بافر اضافه میکند.
  2. Consumer: شامل کد مصرف کننده است. یکی از سایز بافر ما کم کیشود.
  3. Run: این متد در کد بالا دو بار استفاده شده است و هر کدام متد های شماره 1 و 2 را صدا میزنند.
  4. Buildthreads: متد ساختن thread جداگانه برای هر کدام از producer و consumer ما.

قسمتی از خروجی برنامه مسئله تولید کننده و مصرف کننده در جاوا به صورت زیر است:

removed from buffer 0.5550568561090028 and buffer size is 643
removed from buffer 0.9335391776668667 and buffer size is 642
removed from buffer 0.32266321301008183 and buffer size is 641
removed from buffer 0.934943503374314 and buffer size is 640
removed from buffer 0.3942419840105035 and buffer size is 639
removed from buffer 0.6830619572286015 and buffer size is 638
add to buffer 0.17005782496075295 and buffer size is 639
add to buffer 0.528418695479608 and buffer size is 640
add to buffer 0.9307999161009065 and buffer size is 641
add to buffer 0.21563428202924662 and buffer size is 642
add to buffer 0.92539332085157 and buffer size is 643
add to buffer 0.8065441615026954 and buffer size is 644

نوشته های مشابه

2 دیدگاه در “مسئله تولید کننده و مصرف کننده در جاوا (producer consumer)

  1. بهروز گفت:

    سلام.این آموزش رو با بافر محدود نزاشتین؟میشه یه تیکه راهنمایی کنین خودم ویرایشش کنم؟

    1. سلام. بافر ما نا محدود است یعنی Producer تا جایی که بتواند می تواند عدد وارد بافر کند (مگر اینکه حافظه پر شود).

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *