0

Java MultiThreading Wait ve Notify Kavramları – Örnek Uygulama

Merhaba Arkadaşlar bu yazımda java’da Advance ( ileri seviye ) konularından MultiThreading ile ilgili kavramlardan  wait() ve notify()  metodlarından bahsetmeye çalışacağım.  Programcılık gerçek dünyanın dışında bir konu değil zaten o yüzden gerçek dünyadan bir hikaye anlatıp konunun teknik tarafına geçmek istiyorum. Bildiğiniz gibi MultiThreading olayı günümüzdeki bilgisayarların aşırı gelişmişlik düzeyinin sonucu olarak kaçınılmaz.   Bu sebeple bizlerde proje yaparken bu teknolojiyi projelerimize eklemeliyiz. Aksi halde projemizin gelişmişlik seviyesi altlarda olacak. 8 tane çekirdek barındıran bir işlemciyi tek bir thread’e mahkum etmek haksızlık olur değil mi ? O halde aynı anda eş zamanlı bir sürü iş yapalım… işte kısaca Multithreading . 

Tabi bu güzel bir teklif ancak burada şöyle bir durumda karşımıza çıkıyor. Birçok Thread kullancaksanız öyle bir yönetmeniz lazım ki hepsi birbiri ile tam senkron çalışsın . Eğer bu senkronizasyonu sağlayamazsanız projeniz pert olacaktır. Demek MultiThreading güzel bir şey ancak iyi yönetilirse. Trafiğe araç çıkması güzeldir ancak trafik kuralları ve trafik ışıkları düzenli bir şekilde trafiği yönetemezse curcunayı siz düşünün… Şimdi gelilim hikayeye ..

İki tane adam varmış …. Bu iki adam bir kuyu kazma ile görevlendirilmiş . Birisi kazma ile kazacak diğeri ise kürek ile kazmacının kazdığı yeri temizleyecek. Şimdi bu ikisi Kazılacak yerin başına gittiler ve ikisi de çalışmaya başladılar….. bence ikisi de aynı anda başlayamaz…. Neden ? Kazmacının kazması lazım ki ; kürekci temizlesin . Eğer ikisi de birbirine bakmayıp birisi kazılmamış yere kürek sallasa ve diğeri de önünde bir şey var mı yok mu diye kontrol etmese , küreçinin kafasına kazma gelebililir ve kazma işlemi yapılamaz ve kürekcinin de küreği kırılır sonuçta iş yapılamaz… İşte size programın çökmesi….

İşte bu örnekte nasıl olmalı ; kazmacı ile kürekçi senkron bir şekilde çalışmalı . Yani  kazılacak yerin başına gidince önce kürekçi durmalı ve kazmacı biraz kazmalı.. sonra kazmacı çekilmeli ve kürekçi kazılan kısmı temizlemeli ve bu şekilde işlem sonlanmalı. Aslında gerçek dünyada insanlar zaten bunu otomatik yapar ancak bilgisayar’a en bariz bir işi bile söylemezseniz yapmadığı için bunu siz ayarlamalısınız.  İşte ilk başta kürekci wait() durumunda olmalı ve kazmacının notify() yapmasını beklemeli. Kazmacı notify() yapınca kendisi de wait() durumuna geçmeli. Kürekçinin işi bitince kazmacıya notify()  yapmalı ve kendisi de wait() durumuna geçmeli ki senkron bir şekilde iş yapılıp bitsin..

Birden fazla thread’in aynı nesne üzerinde çalıştığı durumlarda bunların uygun bir şekilde koordine edilmesi lazımdır. Aksi halde hatalar oluşacak hatta program kilitlenecektir. Yine başka önemli bir husus olarak erişilen nesnede kullanılan metodlar syncronized  metodlar olmalı. wait() metodu ile bir thread beklemeye alınırken ve notify() metodu ile bekleyen thread çalışmaya devam eder. İşte iki örneğimiz var inşallah anlaşılmıştır . 

// Yazma Okuma Uygulaması 
/*
* bu uygulamada bir mesaj nesnemiz var bu nesneye 2 tane ayrı thread erişip iş yapıyor .
* Thread'lerden birisi nesneye ait mesaj değişkenine yazılan değeri okuma yapıyor 
* diğeri ise mesaj değişkenine yazma yapıyor. 
* Tabi yazma olmadan okuma olmayacağından wait() ve notify() ile nesneler senkronize ediliyor
*/

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
	// write your code here

        Mesaj mesaj=new Mesaj();
        Thread threadOku=new Thread(new OkumaYap(mesaj));
        Thread threadYaz=new Thread(new YazmaYap(mesaj));

        threadOku.start();
        threadYaz.start();

    }
}


class  Mesaj{


    String mesaj="";
    Scanner scanner=new Scanner(System.in);

    public synchronized   void oku(){

        if(!this.mesaj.isEmpty()) {

            System.out.println("Yazılan Mesaj : "+this.mesaj);
            this.mesaj="";
        }
        else
        {
            try {
                System.out.println("Okunması için Bir Mesaj Yazılması Bekleniyor ");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public synchronized void yaz(String mesaj){



        if(this.mesaj.isEmpty()){
        System.out.println("Ekrana Yazma Yapılabilmesi için Bir Mesaj Yazın");
        this.mesaj=scanner.nextLine();
        System.out.println("Mesaj nesnesine yeni bir değer atandı : => "+ this.mesaj);
        notifyAll();}
        else
        {
            try {
                System.out.println("bir mesaj Yazıldı Okunması Bekleniyor");
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }


}


class  OkumaYap implements Runnable{

    Mesaj mesaj;


    public OkumaYap(Mesaj mesaj) {
        this.mesaj = mesaj;
    }

    @Override
    public  void run() {
        while (true){

           mesaj.oku();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

class  YazmaYap implements  Runnable{

    Mesaj mesaj;



    public YazmaYap(Mesaj mesaj) {
        this.mesaj = mesaj;
    }

    @Override
    public void run() {

        while (true){

            mesaj.yaz(mesaj.mesaj);
        }
    }
}
/* üretim ve satım işlemleri yapan bir program
*bu projede de üretilecek malzemeler var ve üretimden sonra üretilen satılacak 
* sonrasında yeni malzeme üretilecek . 
* Malzeme üretilmeden satış işlemine geçilmeyecek . 
* Bu işlemi wait ve notify ile senkronize bir şekilde yapamaya çalıştım.
*/


import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {
	// write your code here

        Urun urun=new Urun();
        new Thread(new uretThread(urun)).start();
        new Thread(new satThread(urun)).start();





    }
}

class Urun {

    ArrayList<String> urunler = new ArrayList<>();

    String[] uretilecekler = {"Deterjan", "Yumuşatıcı", "Selpak", "Çamaşır Suyu"};

    public synchronized   void uret() {


            for(int i=0; i<uretilecekler.length;i++) {

                urunler.add(uretilecekler[i]);
                System.out.println(ThreadRenk.GREEN+uretilecekler[i]+" ürünü üretildi");
                notifyAll();

                try {

                    System.out.println(ThreadRenk.GREEN+"Üretim durdu Satım Bekleniyor");
                    System.out.println();
                    wait();
                    System.out.println();
                    System.out.println(ThreadRenk.YELLOW+" Tekrar Üretime Başlıyoruz");

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

    }


    public synchronized   void sat() {


            while (true) {

                if(urunler.isEmpty()) {
                    try {
                        System.out.println(ThreadRenk.CYAN+"Satma İşlemi İçin Üretim Yapılmamış Beklemek Lazım ");
                         wait();
                        System.out.println(ThreadRenk.RED+"Üretim Yapıldı Satışa Yapılabilir");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                else {
                    System.out.println();
                    System.out.println( ThreadRenk.PURPLE +"*******"+ urunler.remove(0)+" Adlı Ürün Satıldı Yeniden Üretim Yapılsın ********");
                    System.out.println();
                    notifyAll();
                }


            }


    }


}

class  uretThread implements Runnable{

    Urun urun;
    public uretThread(Urun urun) {
        this.urun=urun;

    }

    @Override
    public void run() {
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        urun.uret();
    }
}

class satThread implements Runnable{

    Urun urun;

    public satThread(Urun urun) {
        this.urun = urun;
    }

    @Override
    public void run() {

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        urun.sat();

        }
    }


    class ThreadRenk{
        public static final String BLACK = "\033[0;30m";   // BLACK
        public static final String RED = "\033[0;31m";     // RED
        public static final String GREEN = "\033[0;32m";   // GREEN
        public static final String YELLOW = "\033[0;33m";  // YELLOW
        public static final String BLUE = "\033[0;34m";    // BLUE
        public static final String PURPLE = "\033[0;35m";  // PURPLE
        public static final String CYAN = "\033[0;36m";    // CYAN
        public static final String WHITE = "\033[0;37m";   // WHITE

    }
import java.util.ArrayList;

public class Main {


    /* Bu projede syncronized bloğu kullanılarak thread'ler senkronize edilecek yukarıdaki örnekte wait ve notify ile benzeri yapılmıştı

    * Senaryo :
    *
    * bir SayiUretTuket diye class'ımız olacak bu sınıfa ait iki tane metod olacak
    * bu metodlardan birisi üretim yapacak ürettiğini bir ArrayList'e ekleyecek
    * bir tanede tuketim yapacak metodumuz olacak bu da üretimin hemen ardına bu üretilen
    * sayıyı arraylist'den kaldıracak . Yani sonuçta biri üretir üretmez diğeri kaldıracak
    * bir üretim threadi bir tüketim thread'i sıra ile çalışacak .
    *
    * */
    public static void main(String[] args) {
	// write your code here


        SayiUretTuket sayiUretTuket=new SayiUretTuket();

        Thread uretici=new Thread(new UreticiThread(sayiUretTuket));
        Thread tuketici=new Thread(new TuketiciThread(sayiUretTuket));


        tuketici.start();
        uretici.start();


    }
}


class SayiUretTuket{

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

    String[] sayilar={"1","2","3","4","5","6","eof"};

    public void  uretici(){


            for (String sayi : sayilar
            )
            {

                synchronized (buffer) {

                buffer.add(sayi);
                System.out.println(sayi + " Ekleniyor...");


            }

            try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }




    }

    public void tuketici() {


            while (true) {


                synchronized (buffer) {
                if (buffer.isEmpty()) {
                    // Eğer buffer boş ise dongüye devam etsin
                    continue;
                }
                if (buffer.get(0).toLowerCase().equals("eof")) {
                    // eğer sayılarda sona gelmişse while döngüsünden çıksın
                    return;
                } else {
                    // Eğer buffer'de 0. eleman boş değilse o elemanı çıkarsın
                    System.out.println(buffer.remove(0) + " Elemanı Çıkarıldı");

                }

            }

        }
    }



}

class  TuketiciThread implements Runnable{

    SayiUretTuket sayiUretTuket;

    public TuketiciThread(SayiUretTuket sayiUretTuket) {
        this.sayiUretTuket = sayiUretTuket;
    }

    @Override
    public void run() {

        sayiUretTuket.uretici();

    }
}
class UreticiThread implements Runnable{

    SayiUretTuket sayiUretTuket;

    public UreticiThread(SayiUretTuket sayiUretTuket) {
        this.sayiUretTuket = sayiUretTuket;
    }

    @Override
    public void run() {

        sayiUretTuket.tuketici();

    }
}

 

 

admin

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir