Links
Konular
View Muhammed YÜRÜRDURMAZ's profile on LinkedIn
XuuGo.com - Online Akademi

Spring roo ile bir başlangıç

Spring Roo

Muhtemelen bu ismi ilk defa duydunuz. Kısaca söylemek gerekirse sizin için basit veri işleyen (data-driven) uygulamalar geliştiriyor, proje yönetiyor, log sistemini yönetiyor ... Örnek olarak toplam 10-15 dakikada Spring MVC / JSP/GWT ve Hibernate ile istediğiniz veritabanının kullanarak bi telefon rehberi yapabilirsiniz. Üstelik buna test kodları ve bir çok şey de dahil.

Nasıl mı ? Öncelikli olarak indirip kuralım

Kurulum

Sisteminizde maven yoksa öncelikli olarak maven kurun. Daha sonra http://www.springsource.org/spring-community-download adresinden son versiyorun indirip kurun:

spring-roo-1.2.3.RELEASE.zip

Kurulum işlemi basittir. Zip doaysını açın, bin dizinini PATH e ekleyin. Komut satırından roo.sh (windows için roo.bat) komutunu çalıştırabilirsiniz. Şimdi telefon rehberimize başlayalım.

Önce bir diizn oluşturalım onun içinde çalışalım.:

myururdurmaz@xuugo:~$ mkdir rehber
myururdurmaz@xuugo:~$ cd rehber
myururdurmaz@xuugo:~/rehber$ roo.sh
    ____  ____  ____
   / __ \/ __ \/ __ \
  / /_/ / / / / / / /
 / _, _/ /_/ / /_/ /
/_/ |_|\____/\____/    1.2.3.RELEASE [rev 7fd62b6]


Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
@krimple: On my way to the @RichmondJUG to speak about @SpringRoo add-ons. Looking forward to it!
roo>

gördüğünüz gbi bir komut satırı açıldı. Şimdi projemizi oluşturalım:

roo> project --topLevelPackage com.xuugo.demo.rehber
Created ROOT/pom.xml
Created SRC_MAIN_RESOURCES
Created SRC_MAIN_RESOURCES/log4j.properties
Created SPRING_CONFIG_ROOT
Created SPRING_CONFIG_ROOT/applicationContext.xml
roo>

Oluşan dizin yapısı ::

myururdurmaz@xuugo:~/rehber$ gvfs-tree
file:///home/myururdurmaz/rehber
|-- log.roo
|-- pom.xml
`-- src
    `-- main
        `-- resources
            |-- META-INF
            |   `-- spring
            |       `-- applicationContext.xml
            `-- log4j.properties

Şimdi hint komutu ile yardım alalım bakalım ne diyor ?:

roo> hint
Roo requires the installation of a persistence configuration,
for example, JPA or MongoDB.

For JPA, type 'jpa setup' and then hit TAB three times.
We suggest you type 'H' then TAB to complete "HIBERNATE".
After the --provider, press TAB twice for database choices.
For testing purposes, type (or TAB) HYPERSONIC_IN_MEMORY.
If you press TAB again, you'll see there are no more options.
As such, you're ready to press ENTER to execute the command.

Once JPA is installed, type 'hint' and ENTER for the next suggestion.

Similarly, for MongoDB persistence, type 'mongo setup' and ENTER.
roo>

utunmadan söyleyelim tab tuşu komut tamamlamakta kullanılıyor. Şimdi:

jpa setup

yazıp tab tuşunu 3 defa basalım:

roo> jpa setup --

jpa setup --database    jpa setup --provider

roo> jpa setup --provider
jpa setup --provider
required --provider: The persistence provider to support; no default value
roo> jpa setup --provider

DATANUCLEUS   ECLIPSELINK   HIBERNATE     OPENJPA

roo> jpa setup --provider

gördüğünüz gibi komut tamamlama güzel çalışıyor, bir HIBERNATE yazıp --database için de HYPERSONIC_PERSISTENT seçelim.:

roo> jpa setup --provider HIBERNATE --database HYPERSONIC_PERSISTENT
Created SPRING_CONFIG_ROOT/database.properties
Updated SPRING_CONFIG_ROOT/applicationContext.xml
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Updated ROOT/pom.xml [added dependencies
org.hsqldb:hsqldb:2.2.9,
org.hibernate:hibernate-core:4.1.8.Final,
org.hibernate:hibernate-entitymanager:4.1.8.Final,
org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final,
commons-collections:commons-collections:3.2.1,
org.hibernate:hibernate-validator:4.3.1.Final,
javax.validation:validation-api:1.0.0.GA,
cglib:cglib-nodep:2.2.2,
javax.transaction:jta:1.1,
org.springframework:spring-jdbc:${spring.version},
org.springframework:spring-orm:${spring.version},
commons-pool:commons-pool:1.5.6,
commons-dbcp:commons-dbcp:1.3]
roo>

isterseniz yine hint komutu ile yardım alalım:

roo> hint
You can create entities either via Roo or your IDE.
Using the Roo shell is fast and easy, especially thanks to the TAB completion.

Start by typing 'ent' and then hitting TAB twice.
Enter the --class in the form '~.domain.MyEntityClassName'
In Roo, '~' means the --topLevelPackage you specified via 'create project'.

After specify a --class argument, press SPACE then TAB. Note nothing appears.
Because nothing appears, it means you've entered all mandatory arguments.
However, optional arguments do exist for this command (and most others in Roo).
To see the optional arguments, type '--' and then hit TAB. Mostly you won't
need any optional arguments, but let's select the --testAutomatically option
and hit ENTER. You can always use this approach to view optional arguments.

After creating an entity, use 'hint' for the next suggestion.
roo>

kısaca bir entity oluşturamyı anlatıyor. ent yazıp 2 kere taba basın diyor o zaman karşınıza şu çıkacak:

roo> entity jpa --class

daha sonra class ismini yazın:

roo> entity jpa --class com.xuugo.demo.rehber.Kayit --testAutomatically
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit.java
Created SRC_TEST_JAVA/com/xuugo/demo/rehber
Created SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitDataOnDemand.java
Created SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitIntegrationTest.java
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit_Roo_Configurable.aj
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit_Roo_ToString.aj
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit_Roo_Jpa_Entity.aj
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit_Roo_Jpa_ActiveRecord.aj
Created SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitDataOnDemand_Roo_Configurable.aj
Created SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitDataOnDemand_Roo_DataOnDemand.aj
Created SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitIntegrationTest_Roo_Configurable.aj
Created SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitIntegrationTest_Roo_IntegrationTest.aj
~.Kayit roo>

package isminde otomatik tamamlama çalışıyor. Anca yine de isterseniz ~.Kayit gibi bir form kullanabilirsiniz. Şimdi entity içerisine alanlar ekleyelim.:

~.Kayit roo> field string --fieldName isim --notNull
Updated SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit.java
Updated SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitDataOnDemand_Roo_DataOnDemand.aj
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit_Roo_JavaBean.aj
~.Kayit roo> field string --fieldName telefon --sizeMin 7
Updated SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit.java
Updated SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitDataOnDemand_Roo_DataOnDemand.aj
Updated SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit_Roo_JavaBean.aj
~.Kayit roo> field string --fieldName email --sizeMin 10
Updated SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit.java
Updated SRC_TEST_JAVA/com/xuugo/demo/rehber/KayitDataOnDemand_Roo_DataOnDemand.aj
Updated SRC_MAIN_JAVA/com/xuugo/demo/rehber/Kayit_Roo_JavaBean.aj
~.Kayit roo>

Şimdi test edelim:

~.Kayit roo> perform tests
........
........
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 30.592s
[INFO] Finished at: Sun Mar 10 23:32:26 EET 2013
[INFO] Final Memory: 11M/240M
[INFO] ------------------------------------------------------------------------
~.Kayit roo>

Web katmanını oluşturalım:

~.Kayit roo> web mvc setup
Created ROOT/src/main/webapp/WEB-INF/spring
Created ROOT/src/main/webapp/WEB-INF/spring/webmvc-config.xml
Created ROOT/src/main/webapp/WEB-INF/web.xml
Updated ROOT/src/main/webapp/WEB-INF/spring/webmvc-config.xml
Created ROOT/src/main/webapp/images
Created ROOT/src/main/webapp/images/add.png
Created ROOT/src/main/webapp/images/banner-graphic.png
Created ROOT/src/main/webapp/images/create.png
Created ROOT/src/main/webapp/images/delete.png
Created ROOT/src/main/webapp/images/favicon.ico
Created ROOT/src/main/webapp/images/list.png
Created ROOT/src/main/webapp/images/resultset_first.png
Created ROOT/src/main/webapp/images/resultset_last.png
Created ROOT/src/main/webapp/images/resultset_next.png
Created ROOT/src/main/webapp/images/resultset_previous.png
Created ROOT/src/main/webapp/images/show.png
Created ROOT/src/main/webapp/images/springsource-logo.png
Created ROOT/src/main/webapp/images/update.png
Created ROOT/src/main/webapp/styles
Created ROOT/src/main/webapp/styles/alt.css
Created ROOT/src/main/webapp/styles/standard.css
Created ROOT/src/main/webapp/WEB-INF/classes
Created ROOT/src/main/webapp/WEB-INF/classes/alt.properties
Created ROOT/src/main/webapp/WEB-INF/classes/standard.properties
Created ROOT/src/main/webapp/WEB-INF/layouts
Created ROOT/src/main/webapp/WEB-INF/layouts/default.jspx
Created ROOT/src/main/webapp/WEB-INF/layouts/layouts.xml
Created ROOT/src/main/webapp/WEB-INF/views
Created ROOT/src/main/webapp/WEB-INF/views/header.jspx
Created ROOT/src/main/webapp/WEB-INF/views/menu.jspx
Created ROOT/src/main/webapp/WEB-INF/views/footer.jspx
Created ROOT/src/main/webapp/WEB-INF/views/views.xml
Created ROOT/src/main/webapp/WEB-INF/views/dataAccessFailure.jspx
Created ROOT/src/main/webapp/WEB-INF/views/index-template.jspx
Created ROOT/src/main/webapp/WEB-INF/views/index.jspx
Created ROOT/src/main/webapp/WEB-INF/views/resourceNotFound.jspx
Created ROOT/src/main/webapp/WEB-INF/views/uncaughtException.jspx
Created ROOT/src/main/webapp/WEB-INF/tags/form
Created ROOT/src/main/webapp/WEB-INF/tags/form/create.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/dependency.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/find.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/list.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/show.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/update.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/checkbox.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/column.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/datetime.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/display.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/editor.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/input.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/reference.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/select.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/simple.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/table.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/form/fields/textarea.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/menu
Created ROOT/src/main/webapp/WEB-INF/tags/menu/category.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/menu/item.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/menu/menu.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/util
Created ROOT/src/main/webapp/WEB-INF/tags/util/language.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/util/load-scripts.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/util/pagination.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/util/panel.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/util/placeholder.tagx
Created ROOT/src/main/webapp/WEB-INF/tags/util/theme.tagx
Created ROOT/src/main/webapp/WEB-INF/i18n
Created ROOT/src/main/webapp/WEB-INF/i18n/messages.properties
Created ROOT/src/main/webapp/images/en.png
Updated ROOT/src/main/webapp/WEB-INF/i18n/application.properties
Updated ROOT/src/main/webapp/WEB-INF/web.xml
Updated ROOT/pom.xml [added dependencies
org.springframework:spring-webmvc:${spring.version},
org.springframework.webflow:spring-js-resources:2.2.1.RELEASE,
commons-digester:commons-digester:2.1,
commons-fileupload:commons-fileupload:1.2.2,
javax.servlet.jsp.jstl:jstl-api:1.2,
org.glassfish.web:jstl-impl:1.2,
javax.el:el-api:2.2,
joda-time:joda-time:1.6,
javax.servlet.jsp:jsp-api:2.1,
commons-codec:commons-codec:1.5;
updated project type to war;
added dependency org.apache.tiles:tiles-jsp:2.2.2]
Updated SRC_MAIN_WEBAPP/WEB-INF/views/footer.jspx
~.Kayit roo>

Sonraki komut

~.Kayit roo> web mvc all --package ~.web
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/web
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/web/KayitController.java
Updated SRC_MAIN_WEBAPP/WEB-INF/spring/webmvc-config.xml
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/web/ApplicationConversionServiceFactoryBean.java
Created SRC_MAIN_WEBAPP/WEB-INF/views/kayits
Created SRC_MAIN_WEBAPP/WEB-INF/views/kayits/views.xml
Updated SRC_MAIN_WEBAPP/WEB-INF/views/kayits/views.xml
Updated SRC_MAIN_WEBAPP/WEB-INF/i18n/application.properties
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/web/ApplicationConversionServiceFactoryBean_Roo_ConversionService.aj
Created SRC_MAIN_JAVA/com/xuugo/demo/rehber/web/KayitController_Roo_Controller.aj
Created SRC_MAIN_WEBAPP/WEB-INF/views/kayits/list.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/kayits/show.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/kayits/create.jspx
Updated SRC_MAIN_WEBAPP/WEB-INF/views/menu.jspx
Created SRC_MAIN_WEBAPP/WEB-INF/views/kayits/update.jspx
~.web roo>

Şimdi çıkıp çalıştıralım:

~.web roo> quit
myururdurmaz@xuugo:~/rehber$ mvn tomcat:run
..........

Şimdi projemiz çalıştı adresimiz: http://localhost:8080/rehber

eclipse projesi oluşturmak isterseniz:

roo> perform eclipse
..............
..............
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17:40.389s
[INFO] Finished at: Sun Mar 10 23:58:53 EET 2013
[INFO] Final Memory: 10M/231M
[INFO] ------------------------------------------------------------------------
roo>

Java ile Thread kullanımda wait ve notify

Java Thread wait kullanımı

Bir çoğumuz bir şekilde Thread kullanmıştır. Thread kullanırken bekleme gerek oldupunda bir çoğumuz kötü bir alışkanlık olarak hemen Thread.sleep kullanmayı tercih ederiz.

Konuyu bir örnek ile açıklayalım.

Örnek bir yazıcı kuyruğu:

package com.xuugo.java.thread.wait;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author myururdurmaz
 */
public class YaziciKuyrugu extends Thread {

    private List<File> dosyalar = new ArrayList<>();
    private static final Object lock = new Object();
    private static final YaziciKuyrugu instance = new YaziciKuyrugu();

    public static YaziciKuyrugu getInstance() {
        return instance;
    }

    private YaziciKuyrugu() {
        start();
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(100);//burada sleep olmazsa liste boş olduğunda sürekli dönüp işlemciyi sonuna kadar kullanır
            } catch (InterruptedException ex) {
                break;
            }
            File dosya = null;
            synchronized (lock) {
                if (!dosyalar.isEmpty()) {
                    dosya = dosyalar.get(0);
                    dosyalar.remove(dosya);
                }
            }
            if (dosya != null) {
                System.out.println("Dosya yazdırılıyor ...... " + dosya);
            }
        }
    }

    public void ekle(File dosya) {
        synchronized (lock) {
            dosyalar.add(dosya);
        }
    }
}

şeklinde bir kod kullanırız. Burada farkında olarak veya farkında olmadan gereksiz yere Thread.sleep kullanırız.

Bu yöntemin sonucu olarak: 1. Thread.sleep gereksiz yere işlemci kullanır 2. Kuyruğa arada iş eklense bile gereksiz yere belirtilen süre kadar beklenir.

Bu sorunlar küçük uygulamalar için çok önemli bir soruna sebep olmaz. Ancak büyük ölçekli uygulamalar düşündüğünüzde, örneğin bu kodun 1 hafya boyunca hiç durmadan çalıştığını; o zaman çok ciddi miktarda kaynak ve zaman boşa harcanmış olacaktır.

Şimdi bu kodu başka bir şekilde Object.wait ve Object.notify kullanarak yazalım:

package com.xuugo.java.thread.wait;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author myururdurmaz
 */
public class YaziciKuyrugu2 extends Thread {

    private List<File> dosyalar = new ArrayList<>();
    private static final Object lock = new Object();
    private static final YaziciKuyrugu2 instance = new YaziciKuyrugu2();

    public static YaziciKuyrugu2 getInstance() {
        return instance;
    }

    private YaziciKuyrugu2() {
        start();
    }

    @Override
    public void run() {
        while (true) {
            File dosya = null;
            synchronized (lock) {
                if (dosyalar.isEmpty()) {
                    try {
                        lock.wait();//kuyruğa yeni bir şey eklenene kadar bekle
                    } catch (InterruptedException ex) {
                        break;
                    }
                }
                dosya = dosyalar.get(0);
                dosyalar.remove(dosya);
            }
            if (dosya != null) {
                System.out.println("Dosya yazdırılıyor ...... " + dosya);
            }
        }
    }

    public void ekle(File dosya) {
        synchronized (lock) {
            dosyalar.add(dosya);
            lock.notify();//kuyruğa yeni bir şey eklendi devam et
        }
    }
}

YaziciKuyrugu2 örneğinde ise hiç bekleme ihtiyacı olmadan daha hızlı ve daha az kaynak tükterek aynı işlemi yapabiliriz.

C# ile Thread kullanımı

C# ve Thread

Thread Nedir ?

Thread basitçe eş zamanlı çalışan görev olarak düşünülebilir. Normal işlemciler aynı anda 2 tane işlem yap[a]maz. Yani aynı anda 2 tane program veya bir program aynı anda 2 tane işlem çalıştıramaz. Bu sorunu çok hızlı bir şekilde işten işe atlayarak çözer. Ancak bu işlem çok hızlı gerçekleştiği için biz farketmeyiz.

Niçin kullanılır ?

Banka hesaplarını bir düşünelim, veya bir web sitesini. Birden çok kişi aynı anda işlem yapabiliyor buralarda. Bu işlemlerin bir çoğu thread ile yapılmaktadır. Basitçe her gelen işlem bir thread 'e atanırsa hiçbir istek diğerini kesmeden işlemlerin hepsi birlikte yapılmaktadır ( Basit bir yapıyla düşünecek olursak. Eğer daha detaylara inecek olursak bir çok etkileyen ve etkilenen faktörler olabilir).

Küçük bir örnek

Şimdi ekrana hem “Merhaba Thread” hemde “Hoşgeldin” yazılarını aynı anda yazan küçük bir konsol uygulamasını inceleyelim. Her biri 10'ar defa yazacak ama ikisinin bekleme süresi farklı birisi 0.5 saniye diğeri 1 saniye. Kod:

class Program {
    static void Main(string[] args) {
        Program p = new Program();
        Thread th1 = new Thread(new ThreadStart(p.MerhabaThreadYaz));
        Thread th2 = new Thread(new ThreadStart(p.HosgeldinYaz));
        th1.Start();
        th2.Start();
        Console.ReadKey();
    }

    public void MerhabaThreadYaz() {
        for (int i = 0; i < 10; i++) {
            Console.WriteLine("Merhaba Thread");
            Thread.Sleep(1000);//bir saniye bekle
        }
    }

    public void HosgeldinYaz() {
        for (int i = 0; i < 10; i++) {
            Console.WriteLine("Hoşgeldin");
            Thread.Sleep(500);//yarım saniye bekle
        }
    }

}

Çıktı Şu şekilde olacaktır. Mesajların geliş sıralarına dikkat edin.:

Hoşgeldin
Merhaba Thread
Hoşgeldin
Hoşgeldin
Merhaba Thread
Hoşgeldin
Hoşgeldin
Merhaba Thread
Hoşgeldin
Hoşgeldin
Merhaba Thread
Hoşgeldin
Hoşgeldin
Merhaba Thread
Hoşgeldin
Merhaba Thread
Merhaba Thread
Merhaba Thread
Merhaba Thread
Merhaba Thread

Keywords

lock

Bir objeyi kilitlemeye yarar. Mesela bir banka programı düşünelim (belki biraz klasik oldu ama). Banka hesabımızın 2 adet kartı olsun. Ben bir bankamatikten arkadaşım başka bir bankamatikten aynı anda para çekmeye çalışıyoruz. Her bir işlem ayrı bir thread olacaktır. Bu mantıkla düşünecek olursak, ben kartı taktım ve hesabımdaki 100 lirayı gördüm, arkadaşımda aynı şekilde gördü. Teorimiz kodun şu şekilde çalıştığı

  1. Para miktarını al.
  2. Yeterli para varmı kontrol et.
  3. Yeterli para varsa parayı ver
  4. Çekilen parayı hesaptan düş.

Çok basit adımlar olarak görünüyor. Ama Önce ben 100 lira çekmek için tuşa bastım, hemen arkamdan arkadaş bastı. İşlem iç içe çalışacağı için adımları şu şekilde göstermemiz uygun olur. Benim işlemim, Arkadaşımın işlemi

  1. Para miktarını al.
  2. Para miktarını al.
  3. Yeterli para varmı kontrol et.
  4. Yeterli para varmı kontrol et.
  5. Parayı ver
  6. Parayı ver
  7. Çekilen parayı hesaptan düş.
  8. Çekilen parayı hesaptan düş.

Olay çok basit gibi görünüyor. Ama 5. ve 6. satıra dikkat ederseniz bundan sonra her iki işleme de onay verildiğini göreceksiniz. Ve sonuçta hesap negatif duruma düşecektir. Bunu engellemenin değişik yolları olabilir. Ama bizim konumuz thread olduğu için thread gözüyle bakacağız olaya. Eğer elimizde bir seçenek olsa bu para çekme esnasında hesabı kilitleyebilsek ne güzel olur değilmi ? İşte burada lock deyimi imdadımıza yetişiyor. lock ile hesap objesini hafızada kilitlediğimiz zaman lock mekanizmasının yapısından dolayı işi bitene kadar diğer thread bu objeye ulaşamayacağı için bu işlemi sağlıklı bir şekilde yerine getirebiliriz.:

lock (Hesap) {
    ParaCek();
}

Monitors

Monitör de lock gibi kullanılan aynı thread içindeki adımları izleyen bir mekanizmadır. Yukarıdaki örnek aynı mantıkla monitör ile yazılacak olursa:

System.Object obj = (System.Object)Hesap;
System.Threading.Monitor.Enter(obj);
try {
    ParaCek();
} finally {
    System.Threading.Monitor.Exit(obj);
}

Monitörlerin kullanımı biraz daha zordur. Çünkü lock ile karşılaştırıldığında monitörü kendiniz bırakmak zorundasınız fakat lock blok dışına çıktığı zaman otomatik serbest kalmaktadır. Yani kötü yazılmış bir kodda monitör kullanımında bir obje ömrünün sonuna kadar kilitli kalabilir.

Mutex

Mutex monitör'e benzerdir. Farkı ise farklı process 'ler arasında thread senkronizasyonu yapabilmesidir. Her thread'in sadece 1 tane mutex'i olabilir. Örnek olarak bir uygulamayı sadece 1 defa çalıştırma kodu yazalım:

namespace birTaneCalis {
    static class Program {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() {
            bool calisiyormu;
            Mutex mt = new Mutex(true, "birtanecalis", out calisiyormu);
            if (!calisiyormu) {
                MessageBox.Show("Zaten bir kopya çalışıyor");
                return;
            }

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Yukarıdaki kodda calisiyormu isimli değişkene ilk defa oluşturulup oluşturulmadığı atılıyor. Eğer değer false ise hafızada 1 tane kopya var demektir, uygulamayı kapatmamız gerekir.

Interlocked

C# thread'lerle ilgili ilginç bir sınıf daha barındırıyor. Düşünmüşler ki bu lock sisteminin en çok kullanım yerlerinden birisi bir sayıyı artırmak veya azaltmak. Bunun için bir class hazırlamışlar. İsmi Interlocked. Kısa bir kullanım örneği ile bunun da üzerinden geçelim.:

public int sayac = 0;
Interlocked.Increment(ref sayac);

Peki hayat bu kadar tozpembe mi ?

Thread kullanışlı birşeydir ama ne yaptığınızı biliyorsanız. Fakat tam olarak bilmiyorsanız başınızı çok ağrıtabilecek bir konudur. Thread çalıştırabilmek için sistem kaynak tüketir. Kontrolsüz bir alanda 100.000 adet thread olştuğunu varsayarsak bunu sonucu ne olacak ? Ben merak ettim deneyeceğim.

Kod

static void Main(string[] args) {
    for (int i = 0; i < 100000; i++) {
        Thread th1 = new Thread(new ThreadStart(MerhabaThreadYaz));
        th1.Start();
    }
}

public static void MerhabaThreadYaz() {
        Console.WriteLine("Merhaba Thread");
        Thread.Sleep(500);//yarım saniye bekle
}

Aşağıda da sonuç

Yarım saniyelik bekleme sebebimiz thread'in bir iş yaptığını varsaydık. Programımız 1.1GB ram kullandı. Bu daha programın yarıda kesilmiş hali. Şimdi diyeceksiniz bu kadar thread'i kim oluştururki ? Haklısınız bu kadarını belki bilinçli olarak kullanmayabilirsiniz. Ama yanlış yazılmış bir thread buna sebep olabilir. Veya kontrolsüz açılan thread'ler.

Tema : | edu | duzmetin |