Ağ Sunucusu Programlaması. Bora Güngören Portakal Teknoloji bora@portakalteknoloji.com

Benzer belgeler
Görsel Programlama DERS 11. Görsel Programlama - Ders11/ 1

1. Aşağıdaki program parçacığını çalıştırdığınızda result ve param değişkenlerinin aldığı en son değerleri ve programın çıktısını yazınız.

Java ve Linux. Bora Güngören Portakal Teknoloji Akademik Bilişim

Uzaktan Eğitim Uygulama ve Araştırma Merkezi

BİL132 Bilgisayar Programlama II

Dağıtık Sistemler CS5001

BİL-141 Bilgisayar Programlama I (Java)

BİL-141 Bilgisayar Programlama I (Java)

// hataları işaret eden referans

İş Parçacıkları (Threads)

Java da Soyutlama ( Abstraction ) ve Çok-biçimlilik ( Polymorphism )

JAVA PROGRAMLAMA DİLİ ÖZELLİKLERİ

while(), do-while(), for() M.İLKUÇAR 2010 MAKU-MYO

Programın Akışının Denetimi. Bir arada yürütülmesi istenen deyimleri içeren bir yapıdır. Söz dizimi şöyledir:

BMS-302 İleri Web Programlama. İş Parçacığı (Thread) ve Soket (Socket) Programlama

İŞ PARÇACIKLARI (THREADS)

BMÜ-111 ALGORİTMA VE PROGRAMLAMA AKIŞ KONTROLÜ YRD. DOÇ. DR. İLHAN AYDIN

MAT213 BİLGİSAYAR PROGRAMLAMA I DERSİ Ders 1: Programlamaya Giriş

DÖNGÜLER BMÜ-111 ALGORİTMA VE PROGRAMLAMA-I YRD. DOÇ. DR. İLHAN AYDIN

if (ad == "Sabri") Console.WriteLine("Merhaba Sabri. Ne zamandır gözükmüyodun...");

Programlama Dillerinde Kullanılan Veri Tipleri

İşletim Sistemleri. Dr. Binnur Kurt Omega Eğitim ve Danışmanlık İşletim Sistemleri

BMÜ-112 ALGORİTMA VE PROGRAMLAMA-II LABORATUARI DENEY-2 FÖYÜ

İş Parçacıkları Thread(s)

/*Aşağıda ki kodları doğru şekilde anlar ve kullanırsanız java da sınıfları biraz da olsa anlamış olursunuz.*/

PORT HABERLEŞME SERİ PORT FARUK BOZAN

İNÖNÜ ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ 2. SINIF 1. DÖNEM VERİ YAPILARI DERSİ LABORATUAR ÖDEVİ

Dağıtık Sistemler CS5001

İşletim Sistemlerine Giriş

BIL1202 ALGORİTMA VE PROGRAMLAMAYA GİRİŞ

Görsel Programlama DERS 03. Görsel Programlama - Ders03/ 1

Üst Düzey Programlama

Dağıtık Sistemler CS5001

Java Dersi. Altuğ Bilgin Altıntaş

Giriş. İplik Modeli. geleneksel işletim sistemlerinde her prosesin özel adres uzayı ve tek akış kontrolü var.

DÖNGÜLER (LOOPS) while(), do-while(), for(), foreach()

Chain of Responsibility Tasarım Şablonu KurumsalJava.com

BM-209 Nesne Yönelimli Programlama. Yrd. Doç. Dr. İbrahim Alper Doğru Gazi Üniversitesi Teknoloji Fakültesi Bilgisayar Mühendisliği Bölümü

Bilgisayar Teknolojileri Bölümü Bilgisayar Programcılığı Programı. Öğr. Gör. Cansu AYVAZ GÜVEN

Algoritma ve Programlamaya Giriş II JAVA İLE PROGRAMLAMA. Muhammet BAYKARA

Arayüz soyut metotların oluşturduğu bir koleksyondur. Bir sınıf arayüzü çalıştırırken arayüzün sahip olduğu soyut metotları da miras alır.

Bilgisayar İşletim Sistemleri BLG 312

JAVA DA GİRİŞ/ÇIKIŞ İŞLEMLERİ. Altuğ B. Altıntaş 2003 Java ve Yazılım Tasarımı - Bölüm 9 1

C# Programlama Dili. İlk programımız Tür dönüşümü Yorum ekleme Operatörler

D İ Z İ L E R A R R A Y S

NESNEYE YÖNELİK PROGRAMLAMA

İNÖNÜ ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ 2. SINIF 1. DÖNEM VERİ YAPILARI DERSİ LABORATUAR ÖDEVİ

Proses. Prosesler 2. İşletim Sistemleri

Sunum İçeriği. Programlamaya Giriş

KONTROL YAPILARI JAVADA UC TURLU KONTROL YAPISI VARDIR BUNLAR İF ELSE İF ELSE İF SWİTCH YAPILARIDIR. IF ELSE YAPISI if (deger) { }else {

Liskov Substitution Principle (LSP) Liskov un Yerine Gecme Prensibi KurumsalJava.com

Nesne tabanlı programlama nesneleri kullanan programlamayı içerir. Bir nesne farklı olarak tanımlanabilen gerçek dünyadaki bir varlıktır.

Ders - 7 while döngüsü

PAKET ERİŞİMLERİ SINIFLARIN YENİDEN KULLANIMI. BMU-112 Algoritma ve Programlama-II Yrd. Doç.Dr. İlhan AYDIN

BİL-141 Bilgisayar Programlama I (Java)

BM-209 Nesne Yönelimli Programlama

Uzaktan Eğitim Uygulama ve Araştırma Merkezi

BMÜ-111 Algoritma ve Programlama. Bölüm 5. Tek Boyutlu Diziler

Java da İşleçler, Ders #3 (4 Kasım 2009)

Class PriorityQueue. Class PriorityQueue<E> java.lang.object java.util.abstractcollection<e> java.util.abstractqueue<e> java.util.

Klavyeden Basit Giriş/Çıkış İşlemleri

İçerik. Java da İşleçler, İşleçler. Aritmetik İşleçler - 1. Aritmetik İşleçler - 2. Geçen ders: Bu ders: BS-515 Nesneye Yönelik Programlama

Giriş. geleneksel işletim sistemlerinde her prosesin. aynı adres uzayında birden fazla akış kontrolü gerekebilir

PROSESLER. Proses. Proses

BMÜ-101 ALGORİTMA VE PROGRAMLAMAYA GİRİŞ LABORATUARI

İNÖNÜ ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ 2. SINIF 1. DÖNEM VERİ YAPILARI DERSİ LABORATUAR ÖDEVİ

Karşılaştırma İşlemleri ve Koşullu İfadeler

NESNE YÖNELİMLİ PROGRAMLAMA HAFTA # 11

Endüstri Mühendisliği Bölümü Bilgisayar Programlama Ders Notları

Akış Kontrol Mekanizmaları

Bilgisayar İşletim Sistemleri BLG 312

J A V A D A P R O G R A M D E N E T İ M İ V E O P E R A T Ö R L E R

BİL-142 Bilgisayar Programlama II

İşletim Sistemlerine Giriş

Doğu Akdeniz Üniversitesi Bilgisayar Mühendisliği Bölümü. BLGM 318 Ara Sınavı Đlkbahar Dönemi 13 Nisan Ad, Soyad Öğrenci No.

Nesneye yönelik: Javada herşey bir nesnedir. Java nesne yönelimli olduğu için kolayca geliştirilebilir.

Java da İstemci Tarafı Uygulamalar

İNÖNÜ ÜNİVERSİTESİ MÜH. FAK. BİLGİSAYAR MÜH. BÖL. ALGORİTMA VE PROGRAMLAMA 2 DERSİ LAB. ÖDEVİ

Bire-bir Sahiplik İlişkisi ile İlgili Sorular:

Uzaktan Eğitim Uygulama ve Araştırma Merkezi

Üst Düzey Programlama

Start : Bu method init methodundan hemen sonra çalışır ve applet dosyası yürütülmeye başladığında çalışmaya başlar.

HSancak Nesne Tabanlı Programlama I Ders Notları

Java Class Yapısında Finalize Metotunun Kullanımı

Java 2 Standart Edition SDK Kurulum ve Java ya Giriş

Ders 8 Konu Özeti ve Problemler

Cahit GÜNGÖR Hacettepe Üniversitesi Bilişim Enstitüsü. Sorumluluk Zinciri. Kod Üretme (Code Generation)

Arş.Gör.Muhammet Çağrı Gencer Bilgisayar Mühendisliği KTO Karatay Üniversitesi 2015

Java da Program Denetimi ve Operatörler

KUYRUKLAR QUEUES. Doç. Dr. Aybars UĞUR

İŞLETİM SİSTEMLERİ DÖNEMİÇİ SINAVI

Görsel Programlama 1

Java Uygulama Güvenliği. Bora Güngören Portakal Teknoloji

İşletim Sistemleri. Dr. Binnur Kurt Omega Eğitim ve Danışmanlık İşletim Sistemleri

Öğr. Gör. Musa AYDIN Fatih Sultan Mehmet Vakıf Üniversitesi

Bölüm 24. Java Ağ Uygulamaları 24.1 Java Appletleri. Bir Applet in Yaşam Döngüsü:

JAVA DA İSTİSNALAR VE DOSYA İŞLEMLERİ. Yrd. Doç.Dr. İlhan AYDIN

Ders 8: Metotlar. barisgokce.com

abstract Sınıflar 1 Sınıf sınıf1 new class Ama aşağıdaki şekilde referans alınabilir;

Java String İşlemleri

Transkript:

Ağ Sunucusu Programlaması Bora Güngören Portakal Teknoloji bora@portakalteknoloji.com 1

Genel Sunum Bilgisi ve Lisans Sunum 16 Aralık 2004 günü Erciyes Üniversitesi'nde LKD adına verilmiştir. Sunuma ait notlar GPL belgeleme lisansı ile dağıtılmaktadır ve LKD'den yada sunumu hazırlayan kişiden temin edilebilir. GPL hakkında detaylı bilgi LKD İnternet sitesi olan http://linux.org.tr/ den yada GNU İnternet sitesi olan http://www.gnu.org/ dan alınabilir. Kısaca özetlemek gerekirse, bu sunum notlarından yararlanmakta özgürsünüz. İçinden parçalar alıp kendi materyalinize eklemek isterseniz, kendi materyalinizi de GPL olarak sunduğunuz sürece, bunda da özgürsünüz. 2

Sunum İçeriği Çok kanallı mimarinin gerekleri Java'da kanallar Komut (Command) Tasarım Biçimi İleri kanal teknikleri Kanal grupları Çok kanallı bir ağ sunucusu 3

Çok Kanallı Mimarinin Gerekleri Bir uygulamanın aynı anda birden fazla işi yapması aslında mümkün değildir. Ancak bilgisayarın işletim sistemi sistem kaynaklarını, özellikle de işlemci gücünü, değişik uygulamalar arasında nöbetleşe paylaştırabilir. Bu durumda kullanıcı için aynı anda birden fazla uygulama çalışıyor gibi gözükür. Çok kanallı (multi-threaded) bir uygulama, aynı anda birden fazla küçük uygulama başlatarak bunları yöneten bir uygulamadır. Çok kanallı uygulamaları onlarca yıldır kullanıyoruz. 4

Çok Kanallı Mimarinin Gerekleri Tipik bir çok kanallı uygulamanın karşılaştığı sorunlar nelerdir? Tüm sorunlar bazı ortak kaynaklara aynı anda ulaşmaya çalışan birden fazla kanal olmasından doğar. Aynı anda bir veri tabanına yazan ve bir veritabanından okuyan iki kanal (küçük uygulama) bulunduğunu düşünün. Veritabanından okuyan uygulama işinin ortasındayken işletim sistemi tarafından kenara alınsa ve yazan uygulama başlatılsa ne olur? Yazıcıya veri yollayan iki uygulamadan birisi ötekinin işini bitirmesini beklemeden kendi verilerini yollamaya başlarsa ne olur? Bir uygulama diğeri için gereken dosyayı silerse ne 5

Çok Kanallı Mimarinin Gerekleri Çok kanallı uygulamaların karşılaştığı bu problemlere eşzamanlılık (synchronization) problemleri adını veriyoruz. Tüm eşzamanlılık problemleri temelde benzerdir. Ancak erişilen kaynakların özellikleri nedeni ile değişik şekillerde çözülürler. Bunun dışında kanallarla çalışırken işletim sisteminin sağladığı modelin kendine has yapısından kaynaklanan problemler de yaşanabilir. Windows NT ile gelen ve bugün de kullanılan dinamik öncelik sistemi buna örnektir. (Detayları daha sonra) 6

Çok Kanallı Mimarinin Gerekleri Herhangi bir programlama dilinde çok kanallı uygulamalar (kabaca) aşağıdaki biçimde tasarlanır ve geliştirilir. Her işi yapacak olan kanallar belirlenir. Her kanalık erişeceği kaynaklar belli olduktan sonra eşzamanlılık sorunları kestirilir. Bu sorunlar için eldeki tekniklerle önlem alınır. Sistemdeki kanalları yaratacak ve çalıştıracak ayrı bir uygulama yazılır. Bu uygulamanın kendisi kısa ömürlü olabilir yada sürekli olarak diğer kanalları yönetmek için çalışmaya devam edebilir. Sistem test edilince önceden farkedilmeyen eşzamanlılık sorunları çıkar. Bu sorunlar giderilir. Sorunsuz olan yazılım sistemi yüklenme testine girer. Yeni problemler bulunur ve giderilir. 7

Java dili 1996 yılında tasarlandığı zaman en baştan çok kanallı olarak tasarlanmıştır. En ilkel main(string args[]) uygulamaları haricinde tüm Java uygulamaları kendiliğinden çok kanallıdır. Ancak bu uygulamaların çoğunda eşzamanlılık sorunları sınıf kitaplıkları içinde çözülmüştür. Bu nedenle programcı çok kanallı sistemin farkına varmadan işini yapar. Bu yaklaşım nedeni ile zaman zaman çok kanallı sistemde güvenli (thread safe) olmayan bazı sınıf kitaplıklarını sanki güvenliymişçesine kullanıyoruz. Bu en sık rastlanan kanal hatalarından birisidir. 8

Java 1.4 kanal mimarisi POSIX standartında belirtilen kanal mimarisine oldukça yakındır. Ancak her işletim sisteminin bu teknikleri desteklemeyeceği varsayımı ile sadeleştirilmiştir. Daha önceden POSIX kanalları (pthread) ile çalışmış birisi için Java kanallarını kullanmak çok kolaydır. Java sanal makinası kendi üzerindeki her kanalı işletim sistemindeki bir kanala (yada sürece) eşlemeye çalışır. Görsel bileşenlerin olduğu uygulamalarda ise durum biraz farklıdır. Kanal özelliği olan görsel bileşenleri yönetecek ayrı bir kanal bulunmaktadır. Ancak uygulamalar yönetimi bu kanala bırakmadan da yazılabilir. 9

Java kanal mimarisinde tüm kanallar Runnable (çalışabilir) adındaki bir arabirimi uygulamaktadır. Runnable arabiriminde tanımlanan tek yöntem, kanal çalıştırıldığında yapılacak olan işlerin yazıldığı run() yani çalış yöntemidir Bu arabirimi uygulayan ve kanallar için ciddi avantajlar sağlayan bir sınıf ise Thread sınıfıdır. Thread sınıfı kendi içerisinde bir Runnable nesnesi (yani bu arabirimi uygulayan herhangi bir sınıfın nesnesi) barındıracak şekilde tasarlanmıştır. Bu nedenle eğer Runnable arabirimini uygulayan herhangi bir sınıfı yazarsak, o sınıfın nesnelerini birer Thread nesnesi içine saklayarak çalıştırabiliriz. 10

public interface Runnable { public abstract void run(); public class Thread implements Runnable { //... 11

Bir Thread nesnesi yaratılırken (yapıcı çağrısı olurken) init() yöntemi kullanılarak içindeki veriler yapılandırılır. private void init(threadgroup g, Runnable target, String name, long stacksize) Buradaki parametreler g, kanalın ait olduğu kanal grubuna referans target, kanalın çalıştıracağı Runnable nesnesi name, kanalın adı stacksize, kanalın kullanacağı yığının maksimum boyutu (bayt olarak). Ancak sıfır girilirse bir sınıf olmaz. 12

Şimdi bu sınıfın en çok kullanılan dört yapıcısını tanıyalım: Varsayılan yapıcı kanalı herhangi bir gruba dahil etmeden, çalıştıracağı bir Runnable olmadan, otomatik yaratılan bir isim ile ve sınırsız yığın boyutu ile yaratır. public Thread() { init(null, null, "Thread-" + nextthreadnum(), 0); Tek parametre olarak Runnable referansı alan yapıcı en yaygın kullanılan yapıcıdır. Bu yapıcı ile kanala kendisinin çalıştıracağı bir nesne veririz. public Thread(Runnable target) { init(null, target, "Thread-" + nextthreadnum(), 0); 13

Yapıcılara devam edelim Runnable ve String parametreleri alan yapıcı, kanalın hedefini ve adını belirler. public Thread(Runnable target, String name) { init(null, target, name, 0); Kanal grubu, hedef ve isim alan yapıcı ise kanalın bu üç parametresini ayarlar. public Thread(ThreadGroup group, Runnable target, String name) { init(group, target, name, 0); 14

Kanallarla çalışırken ilk öğrenilen yöntem currentthread() yöntemidir. public static native Thread currentthread(); Bu yöntem sınıfın durağan bir yöntemi olarak o sırada çalışmakta olan kanala bir referans döner. Dikkat ederseniz bu yöntemi çağırdığımız zaman çalışan kanal içinde bulunduğumuz kanal olacaktır. Bu durumda kendi kanalımıza referans elde etmiş ouruz. Bu yöntemin döndüğü değeri this yada super referanslarını kullandığımız gibi kullanmamız gerekir. 15

Kanallarla çalışırken ilk öğrenilen yöntem currentthread() yöntemidir. public static native Thread currentthread(); Bu yöntem sınıfın durağan bir yöntemi olarak o sırada çalışmakta olan kanala bir referans döner. Dikkat ederseniz bu yöntemi çağırdığımız zaman çalışan kanal içinde bulunduğumuz kanal olacaktır. Bu durumda kendi kanalımıza referans elde etmiş ouruz. Bu yöntemin döndüğü değeri this yada super referanslarını kullandığımız gibi kullanmamız gerekir. 16

İlk kanal uygulamamız: class Kanal1 { static java.lang.runnable r; static java.lang.thread t; public static void main(string args[]){ r = t = Thread.currentThread(); System.out.println(t.toString()); 17

Bu uygulamanın tipik çıktısı aşağıdaki gibidir: Thread[main,5,main] Burada elde edilen bilgiler sırası ile Kanalın sınıfı Kanalın adı Önceliği Kanal grubunun adı 18

Burada tostring() yönteminin kodu açıklayıcı olacaktır. public String tostring() { ThreadGroup group = getthreadgroup(); if (group!= null) { return "Thread[" + getname() + "," + getpriority() + "," + group.getname() + "]"; else { return "Thread[" + getname() + "," + getpriority() + "," + "" + "]"; 19

Kendi kanal sınıfımızı yazarken aşağıdakileri yazmamız gerekir. Yapıcı(lar) run() yöntemi Aslında eğer sınıfımız içinde veri barındırmıyorsa yapıcı yazılmasına gerek olmaz ancak genelde kanal sınıflarının eriştikleri belli kaynaklar olacaktır ve bu kaynaklara referanslara sahip olmaları gerekir. 20

class Kanalim1 extends Thread { private static int sayac = 0; private static int sayac() { return Kanalim1.sayac++; Kanalim1(){ super("kanalim1-" + Kanalim1.sayac()); 21

public void run(){ System.out.println("Su anda " + this.getname() + " calisiyor"); 22

Kanallar her ne kadar çalıştırıldıklarında run() yöntemini kullansalar da, çalıştırılmaları için işletim sisteminin kanal kuyruğuna girmeleri gerekir. Bu kuyruğa girmeleri için önce onların start() yöntemi çalıştırılır. Kuyruğa giren kanal, bir diğer kanal işini bitirene kadar bekleyecektir. 23

class Kanal2 { public static void main(string args[]){ Thread t1 = new Thread( new Kanalim1() ), t2 = new Kanalim1(); System.out.println("Baslatiyorum."); t1.start(); t2.start(); System.out.println("Baslattim."); 24

Bu uygulamanın çıktısı aşağıdaki gibi: Baslatiyorum. Baslattim. Su anda Kanalim1-0 calisiyor Su anda Kanalim1-1 calisiyor Görüldüğü gibi kanalları yaratan esas kanalın işi bitmeden diğerleri başlayamadı. Bu durumda, pratik uygulamada her kanalın gönüllü olarak çalışmayı bırakması ve diğer kanallara fırsat vermesi gereklidir. 25

Bir kanalın gönüllü olarak çalışmaya ara vermesi genellikle uykuya yatması (sleep) mekanizması ile olur. public static native void sleep(long millis) throws InterruptedException; Burada hata durumu oluşabileceğine dikkat edin. Eğer bu kanal uykuya yatmak isterken yada uykudayken durumu bir diğer kanal tarafından bölünürse bu hata durumu oluşur. Bu nedenle bir kanalın uykuya yattığı kodlar try-catch bloğunda olmak zorundadır. 26

Şimdi uyuma/uyanma mekanizmasını kullanan bir örnek yapalım. İki kanalımız olacak. Birincisi dosyaya yazacak ve uykuya yatacak. İkincisi dosyadan okuyacak ve uykuya yatacak. 27

import java.io.*; class Kanalim2 extends Thread { private FileInputStream fis; private boolean hazir; 28

import java.io.*; class Kanalim2 extends Thread { private FileInputStream fis; private boolean hazir; Kanalim2 (String dosya){ hazir = false; 29

try { fis = new FileInputStream(dosya); hazir = true; catch(filenotfoundexception fnfe){ System.err.println("Dosya bulunamadi."); catch(ioexception ioe){ ioe.printstacktrace(system.err); 30

public void run(){ byte baytlar[] = new byte[6]; int offset = 0; int n = 5; while(true){ int okundu = 0; try{ if (hazir == true) okundu = fis.read(baytlar); 31

catch(ioexception ioe){ ioe.printstacktrace(system.err); okundu = 0; if (okundu == 0){ System.out.println("Okunacak yazi kalmadi."); break; 32

String s = null; try { s = new String (baytlar,"iso-8859-9"); catch(unsupportedencodingexception uee){ uee.printstacktrace(system.err); s = null; System.out.println(s+" okundu."); 33

int saniye = 2; try{ Thread.currentThread().sleep(saniye * 1000); catch(interruptedexception ie){ ie.printstacktrace(system.err); 34

try{ fis.close(); catch(ioexception ioe){ ioe.printstacktrace(system.err); 35

class Kanalim3 extends Thread { private FileOutputStream fos; private boolean hazir; Kanalim3(String dosya){ hazir = false; try{ boolean ekle = true; fos = new FileOutputStream(dosya,ekle); hazir = true; 36

catch (FileNotFoundException fnfe){ fnfe.printstacktrace(system.err); catch(ioexception ioe){ ioe.printstacktrace(system.err); 37

public void run(){ String s = null; int n = 5; while (n > 0){ s = "Dene-" + n; n--; 38

try { if (hazir == true){ byte[] baytlar = s.getbytes(); fos.write(baytlar); System.out.println( "Dosyaya " + s+ " yazdim."); 39

catch(ioexception ioe){ ioe.printstacktrace(system.err); try { int saniye = 2; Thread.currentThread().sleep(saniye * 1000); catch(interruptedexception ie){ ie.printstacktrace(system.err); 40

try { fos.close(); catch(ioexception ioe){ ioe.printstacktrace(system.err); 41

class Kanal3 { public static void main(string args[]){ java.util.random r = new java.util.random( System.currentTimeMillis() ); int karakter = Math.abs (r.nextint())%8 + 1; 42

// rastgele dosya adı yaratalım String s = ""; while(karakter-- > 0){ s = s + (char)( 'a' + Math.abs (r.nextint())% 26 ); s = s + ".txt"; 43

File f = new File (s); boolean yaratildi = false; if (f.exists() == false){ try { yaratildi = f.createnewfile(); catch(ioexception ioe){ ioe.printstacktrace(system.err); 44

if (yaratildi == false) return; String ad = f.getpath(); Thread t1 = new Kanalim3(ad); // yazici Thread t2 = new Kanalim2(ad); // okuyucu 45

t1.start(); t2.start(); int saniye = 15; try { Thread.currentThread().sleep(saniye * 1000); catch(interruptedexception ie){ ie.printstacktrace(system.err); System.out.println("Bitti"); 46

Bu uygulamayı çalıştırdığımızda ne oluyor? 47

Bir problem var. Bu okuyucu kanalda oluyor. Dosyanın son satırını defalarca okuyoruz. Okuyucu kanalın dosyaya her zaman yazılacağını varsaymak yerine daha başka bir biçimde yazılması gerekli. Belki de yazıcı kanal, okuyucu kanala kendisinin bir şey yazdığını belirtmeli. Bu durumda iki kanal uygulama uzayında bir değişkeni paylaşabilir. Yazıcı yazdıkça bu değişkene müdahale eder. Örneğin artırır. Okuyucu uyandığında değişkene bakar, pozitif ise okur; okudukça azaltır. Peki aynı anda yazıcı da okuyucu da uyanık olursa ne olur? 48

Okuyucu/Yazıcı problemi eşzamanlılık problemlerinin en klasiğidir. Şu andaki hali ile bu problem üretici/tüketici sınıfı problemlere girer. Tüketiciler üretilmeden tüketemezler. Bunu sağlamak için karşılıklı ayrım (mutual exclusion) sağlanması gerekir. Karşılıklı ayrımı sağlamanın klasik bir yolu bir mutex değişkeni yada bir semafor kullanmaktır. 49

class VeriYapisi { public void ekle(int i){ System.out.println("ekle"); try{ Thread.currentThread().sleep(Paylasilan.SURE); catch(java.lang.interruptedexception ie){ 50

public void cikar(int i){ System.out.println("cikar"); try{ Thread.currentThread().sleep(Paylasilan.SURE); catch(java.lang.interruptedexception ie){ 51

class Paylasilan { public static final int N = 10; public static final int SURE = 1000; // 3 semafor public static boolean mutex= true; //acik/kapali tipi public static int bos = 1; // sayac tipi public static int dolu = 9; //sayac tipi public static VeriYapisi vy = new VeriYapisi(); 52

class Uretici implements Runnable { public void run(){ while(true){ // uret... 53

if(paylasilan.mutex == true){ int urun=1; Paylasilan.bos--; Paylasilan.mutex = false; // girdim System.out.println("Uretici girdi."); Paylasilan.vy.ekle(urun); System.out.println("Uretici cikti"); Paylasilan.mutex = true; // ciktim 54

Paylasilan.dolu++; if (Paylasilan.dolu == Paylasilan.N) try{ Thread.currentThread().sleep(Paylasilan.SURE); catch(java.lang.interruptedexception ie){ 55

else { System.out.println("Uretici bekliyor."); try{ Thread.currentThread().sleep(Paylasilan.SURE/2); catch(java.lang.interruptedexception ie){ 56

class Tuketici implements Runnable { public void run(){ while(true){ // tuket... 57

if(paylasilan.mutex == true){ int urun=1; Paylasilan.dolu--; Paylasilan.mutex = false; // girdim System.out.println("Tuketici girdi"); Paylasilan.vy.cikar(urun); System.out.println("Tuketici cikti"); Paylasilan.mutex = true; // ciktim 58

Paylasilan.bos++; if (Paylasilan.bos == Paylasilan.N) try{ Thread.currentThread().sleep(Paylasilan.SURE); catch(java.lang.interruptedexception ie){ 59

else { System.out.println("Tuketici bekliyor."); try{ Thread.currentThread().sleep(Paylasilan.SURE/2); catch(java.lang.interruptedexception ie){ 60

class UreticiTuketici { public static void main(string args[]){ Thread t1 = new Thread(new Uretici(),"Uretici"); Thread t2 = new Thread(new Tuketici(),"Tuketici"); t1.start(); t2.start(); 61

Kendi semaforlarımız ile yazdığımız çözüm çok hoş oldu ama giderek artan sayıda paylaşılan kaynak için daha merkezi bir çözüm olmalıdır. Java'da her nesne için bir izleme durumu (monitor state) bulunur. Nesnenin bu durumunda ona aynı anda yalnızca bir kullanıcının erişmesi sağlanır. İzleme durumunu seçimlerde oy sandığının olduğu kabine benzetebilirsiniz. Bir kişi kabine girdiğinde, o çıkana kadar kimse kabine giremez. Burada monitör durumu kabin, kullanıcılar kişiler ve erişilen nesne de oy sandığı olacaktır. 62

Ancak izleme durumu tekniği pahalı bir tekniktir. Bu nedenle Java'da her nesnenin izleme durumu aktif olmaz. Bizim o nesnenin durumunu açıkça aktif hale getirmemiz gerekir. Bir nesnenin izleme durumunu aktif hale getirmek için synchronized (eşzamanlı) anahtar sözcüğünü kullanırız. synchronized (nesne) { // burada nesneye olan erişim izleme durumunda 63

Zaman zaman bir sınıfın belli bir yöntemi çağrıldığında yöntem bitene kadar izleme durumunda kalınması da gerekli olabilir. Bu durumda yöntemi nitelediğimiz sözcüklere (public, static, vs.) synchronized sözcüğünü ekleriz. public synchronized void f() { // izleme durumundayız 64

Kanallar söz konusu olunca verilen bir örnek bir yazıcıya yazı yazdırmak isteyen iki uygulamadır. Tipik olarak, işletim sistemi tarafından sağlanan basit bir servisi kullanan iki ayrı kanal olacaktır. Bu kanalların eşzamanlı çalışması için yazıcıyı simgeleyen nesnenin izleme durumuna sokularak çalışılması yada servisin kendisinin izleme durumunda olması gereklidir. Örnekleyelim. 65

class Yazici { public static final int SURE = 1000; // synchronized // birazdan açacağız public void yazdir(string metin){ System.out.print("Ust bilgi :: "); try{ // metni cekiyor. Thread.sleep(Yazici.SURE); 66

catch (java.lang.interruptedexception ie){ System.out.print(metin); System.out.println(" :: Alt bilgi"); 67

class Ofis implements Runnable { String s; Yazici y; Ofis(String s, Yazici y){ this.s = s; this.y = y; 68

public void run(){ y.yazdir(s); 69

class Synch1 { public static void main(string args[]){ Yazici y = new Yazici(); Thread bir = new Thread (new Ofis("bir",y)); Thread iki = new Thread (new Ofis("iki",y)); bir.start(); iki.start(); 70

Kodda şu anda eşzamanlılık desteği yok // synchronized // birazdan açacağız public void yazdir(string metin){ Sonuç aşağıdaki gibi oluyor. Hataya dikkat edin. Ust bilgi :: Ust bilgi :: bir :: Alt bilgi iki :: Alt bilgi Eşzamanlılık desteğini açalım synchronized // birazdan açacağız public void yazdir(string metin){ Sonuç aşağıdaki gibi oluyor. Ust bilgi :: bir :: Alt bilgi Ust bilgi :: iki :: Alt bilgi 71

Aynı örneği bu kez de yazıcıyı simgeleyen nesneyi eşzamanlı olarak tutarak yapalım. Yazici sınıfında eşzamanlılıkla ilgili bir şey yapmıyoruz. Bu mantıklı bir durum olabilir. Çünkü çoklukla üçüncü kişilerin hazırladığı ve kanal güvenliği (thread safety) akılda tutulmadan yazılmış sınıfları kullanırız. Kanal güvenliği performansı bir miktar düşürdüğü için bazen bilinçli olarak göz ardı edilir. 72

class Ofis implements Runnable { // aynı veriler ve yapıcı public void run(){ synchronized(y){ y.yazdir(s); 73

Bu durumda çıktı yine olması gerektiği gibi doğru olacaktır. Java'daki izleme durumu tekniği masrafına rağmen çok iyi çalışmaktadır. Nadiren kendi semaforlarımızı yazmamız gerekir. 74

Komut Tasarım Biçimi 75

Komut Tasarım Biçimi Bir Komut nesnesinin tek becerisi, istendiği zaman işletilebilmesidir. Komut ne yapacağını kendisi bilir. Alıcı sınıf, Komut nesnesi üzerinde çeşitli ayarlar yapabilse de komutun ne yapacağı yine kendisine kalmıştır. Bu bize bir Runnable nesnesini ve onun run() yöntemini hatırlatıyor. Ayar gerektirmeyen basit bir komut Runnable arabirimini uygulayan bir anonim iç sınıf (anonymous inner class) nesnesi olarak yazılabilir. Bu şekildeki komutları serileştirme ile saklayabilir ve RMI ile kolayca uzak bilgisayarlara da aktarabiliriz. 76

Komut Tasarım Biçimi import java.util.list; import java.util.arraylist; class KomutVerici extends Thread { private Alici hedef; public KomutVerici(Alici hedef){ this.hedef = hedef; 77

Komut Tasarım Biçimi public void run(){ Runnable komut = new Runnable(){ public void run(){ System.out.println("komut isletildi."); ; // komut hazır alıcıya geçilecek hedef.komutal(komut); System.out.println("KomutVerici kapaniyor."); 78

Komut Tasarım Biçimi class Alici extends Thread{ List<Runnable> liste; Alici(){ liste = new ArrayList<Runnable>(5); public void komutal(runnable komut){ liste.add(komut); 79

Komut Tasarım Biçimi public void run(){ System.out.println("Komutlar isletiliyor"); for (Runnable komut : liste){ Thread t = new Thread (komut); t.start(); 80

Komut Tasarım Biçimi class Komut{ public static void main(string args[]){ System.out.println("Kanallar yaratiliyor"); Alici al = new Alici(); KomutVerici kv = new KomutVerici(al); 81

Komut Tasarım Biçimi kv.start(); al.start(); try { Thread.currentThread().sleep(5000); catch(interruptedexception ie){ ie.printstacktrace(system.err); System.out.println("Hersey bitti."); 82

Komut Tasarım Biçimi Uygulama çalıştırıldığı zaman çıktı aşağıdaki gibi Kanallar yaratiliyor KomutVerici kapaniyor. Komutlar isletiliyor komut isletildi. Hersey bitti. Komutu veren kanal kapatıldıktan sonra bile komut işletilebildi. Aslında bir komut elden ele gezebilir. Bu şekildeki bir yapıya Sorumluluk Zinciri (Chain of Responsibility) adı verilir. C++ ve Java'daki hata durumu işleme mekanizması tipik bir sorumluluk zinciridir. 83

Komut Tasarım Biçimi 84

İleri Kanal Teknikleri Kanallar arası haberleşme için uyuma/uyanma tekniğini kullanarak işlemlerin belli bir sıra ile olmasını garantiye alıyorduk. Ancak işletim sisteminde çalışan başka kanallar da vardır. Bu kanallara ayrılan zamanın kaç milisaniye olacağını öngöremeyiz. Bu nedenle hassas eşgüdüm için uyuma uyanmaya güvenemeyiz. Özellikle bir kanalın bir diğer kanalın uyumasını ve uyanmasını beklemesi, bir diğerine haber vermesi gibi konularda uyuma/uyanma yetersiz kalır. 85

İleri Kanal Teknikleri Problem: Bir kanalın uyuma/uyanma mekanizması kullanmak yerine çok kısa bir süre için kenara çekilmesi ve böylece diğer kanallardan birisinin devreye girebilmesi. Çözüm: Thread sınıfındaki yield() yöntemi şu anda çalışan kanalın anlık olarak durdurulmasını sağlar. public static native void yield(); Örnekleyelim. 86

İleri Kanal Teknikleri class GonulluCekilen extends Thread{ public void run(){ for(int i=0; i<5;i++){ System.out.println("Uzun suren is"); System.out.println("GonulluCekilen cekildi"); Thread.yield(); 87

İleri Kanal Teknikleri class FirsatKollayan extends Thread { public void run(){ System.out.println("minik is"); 88

İleri Kanal Teknikleri class Yield { public static void main(string args[]){ Thread kanallarim[] = new Thread[5]; kanallarim[0] = new GonulluCekilen(); kanallarim[0].start(); for(int i = 1; i< kanallarim.length; i++){ kanallarim[i] = new FirsatKollayan(); kanallarim[i].start(); 89

İleri Kanal Teknikleri Uygulama çalışınca çıktısı aşağıdaki gibi oluyor: Uzun suren is GonulluCekilen cekildi Uzun suren is GonulluCekilen cekildi minik is minik is minik is minik is Uzun suren is GonulluCekilen cekildi Uzun suren is GonulluCekilen cekildi Uzun suren is GonulluCekilen cekildi 90

İleri Kanal Teknikleri Java'da herhangi bir nesnenin izleme durumunu kullanmak için Object sınıfında yazılan iki temel yöntem vardır. wait() yöntemi, bu nesneye erişen kanalın başka bir kanal nesnenin notify() yöntemini (yada notifyall() yöntemini) çağırana kadar beklemesini sağlar. Bu yöntem izleme durumunun (monitor state) sahip değiştirmesine dayanır. synchronized (nesne) { while (<koşul sağlanmıyor>) nesne.wait(); // artık işlerini yapabilir. notify() yöntemi ise nesneyi bekleyen rastgele bir kanalı uyandıracaktır. 91

Kanal Grupları Java'da her kanalın bir Kanal Grubu (Thread Group) içinde bulunması önemli bir prensiptir. Kanal grupları kanalları ve başka kanal gruplarını içerecek biçimde organize edilmiş bir ağaç yapısıdır. Bu yapı bir bileşke (composite) örneğidir. Yapının tepesindeki (kökündeki) kanal grubu hariç tüm kanal gruplarının bir ebeveyni (parent) bulunacaktır. Birinci temel prensip, her seviyedeki kanal gruplarının doğrudan içinde bulunan kanalın sadece kendi kanal grubu hakkında bilgi edinmesi ve kanal grubu üzerinde toplu işlem yapmasıdır. İkinci temel prensip, bir kanal grubunun ağacın sadece bir seviyesindeki kanalları kilitlemeye hakkı olmasıdır. 92

Kanal Grupları 93

Kanal Grupları Kanal gruplarını uygulamak için ThreadGroup sınıfını kullanırız. add(thread t) yöntemi ile gruba kanal eklenebilir remove(thread t) yöntemi ile de belli bir kanal gruptan çıkabilir. list() yöntemi ile kanal grubunu listeleyebiliriz. activecount() yöntemi ile kanal grubu ve altındaki kanal gruplarında etkin durumdaki toplam kanal sayısı hakkında yaklaşık bir sayı alabiliriz. enumerate(thread[] list) yöntemi ile kanal grubundaki aktif kanallara referansları aktarılan Thread dizisine yazabiliriz. Eğer dizi yeterince uzun değilse bazı kanallar için olan referanslar yazılmayacaktır. 94

Kanal Grupları class Kanalim extends Thread { private static int serino = 0; private int benimnumaram; Kanalim(){ benimnumaram = ++serino; 95

Kanal Grupları Kanalim(ThreadGroup grup){ super(grup,"kanalim"); benimnumaram = ++serino; public String tostring(){ return benimnumaram + "numarali Kanalim."; 96

Kanal Grupları public void run(){ System.out.println(this.toString() + "basladi."); for (int i = 0; i<2; i++) try { System.out.println(this.toString() + "uykuya yatiyor"); Thread.sleep(1000); System.out.println(this.toString() + "uyandi"); 97

Kanal Grupları catch(interruptedexception ie){ System.out.println(this.toString() + "kapaniyor."); 98

Kanal Grupları class KanalGrubu { public static void main(string args[]){ ThreadGroup grup = new ThreadGroup("grubum"); for(int i=0; i<2; i++){ (new Kanalim(grup)).start(); 99

Kanal Grupları System.out.println("main cekiliyor."); Thread.yield(); System.out.println("main geri geldi."); System.out.println(); int aktif = grup.activecount(); System.out.println("Grupta " + aktif + " aktif kanal var."); grup.list(); System.out.println(); 100

Kanal Grupları System.out.println("main cekiliyor."); Thread.yield(); System.out.println("main geri geldi."); System.out.println("Grubu donduruyorum."); grup.suspend(); aktif = grup.activecount(); System.out.println("Grupta " + aktif + " aktif kanal var."); grup.list(); System.out.println(); 101

Kanal Grupları System.out.println("main cekiliyor."); Thread.yield(); System.out.println("main geri geldi."); System.out.println("Grup geri gelsin."); grup.resume(); System.out.println("main bitti..."); 102

Kanal Grupları main cekiliyor. 1numarali Kanalim.basladi. 1numarali Kanalim.uykuya yatiyor 2numarali Kanalim.basladi. 2numarali Kanalim.uykuya yatiyor main geri geldi. Grupta 2 aktif kanal var. java.lang.threadgroup[name=grubum,maxpri=10] 1numarali Kanalim. 2numarali Kanalim. 103

Kanal Grupları main cekiliyor. main geri geldi. Grubu donduruyorum. Grupta 2 aktif kanal var. java.lang.threadgroup[name=grubum,maxpri=10 ] 1numarali Kanalim. 2numarali Kanalim. main cekiliyor. main geri geldi. Grup geri gelsin. main bitti... 104

Kanal Grupları 1numarali Kanalim.uyandi 1numarali Kanalim.uykuya yatiyor 2numarali Kanalim.uyandi 2numarali Kanalim.uykuya yatiyor 1numarali Kanalim.uyandi 1numarali Kanalim.kapaniyor. 2numarali Kanalim.uyandi 2numarali Kanalim.kapaniyor. 105

Çok Kanallı Bir Ağ Sunucusu Çok kanallı bir ağ sunucusu aşağıdaki biçimde oluşacaktır. Yönetici kanal diğer kanalları yaratmaktan ve istemcilerden gelen bağlantıları bu kanallara bağlamaktan sorumludur. Yönetici kanalın bir daemon kanal olması yararlıdır. Diğer kanallar ise sadece gelen istemci bağlantılarını işler. Yönetici kanal her kanala belli bir zaman aşımı yada belli bir sayıda istemci isteği atar. Bu ikisinden birisi geçildikten sonra ilk fırsatta kanalı kapatır. 106

Çok Kanallı Bir Ağ Sunucusu 107