25 Mart 2010 Perşembe

Swing ve EDT (Event Dispatch Thread)'ın Önemi

Java AWT'nin önemli bir parçası EDT dir. AWT bize hangi sistem altında çalışırsak çalışalım pencere sistemini soyutlayan bir sistemdir. Bu sistemin varlığının sebebi çeşitli işletim sistemlerinin farklı pencere sistemlerine sahip olmasından kaynaklanıyor. Java iddası gereği (Platformdan bağımsız olma) AWT ile beraber üzerinde çalıştığı sistemin pencere yöneticisine bağlantı kurmamızı sağlayan bir sistem sağlamak için adı üzerinde soyut (abstract) bir araç-kiti (toolkit) olan  AWT'yi sunuyor. EDT ise bunun bir parçası demiştik. Görsel öğeler eğer kullanıcının hareketlerine yanıt veriyor ve çoğu zaman bir işlem gerçekleştirilmesini sağlıyorsa birer kullanıcı arayüzü (GUI) haline gelirler. Örneğin yaz tatilinde çekilmiş olduğunuz bir resim sizi internete bağlamayacaktır yada üzerine fareyi getirdiğinizde bir tepki vermeyecektir. O zaman bir kullanıcı arayüzünde o kullanıcıya cevap veren durumlar ve bu durumların ürettiği bazı olaylar vardır. Mesela bir düğmeye tıklamak bir menüyü seçmek bir olay yaratır. Bu olayın işlenmesi ve gerekiyorsa görsel bir bildirimde bulunulması işi önemlidir.

Bildiğiniz gibi biz programlarımızı farklı işlemleribağımsız olarak yürütülecek şekilde tasarlıyabiliyoruz. Bu işlemleri ayrı kanallarda yaparken grafik arayüz ile ilgilenmeye başlayınca aklımıza kullanıcı arayüzünün de performans açısından çok kanallı tasarlanabilineceği aklımıza gelmiş olabilir. Ancak gerçekte çoğu çizim işlemi ve olay yönetimi tek kanalda yapılacak şekilde dizayn edilir.

Not: Swing içerisinde her zaman tek kanallık söz konusu olmaya bilir. Bazı çalışma zamanı ortamlarında çok kanallı yaklaşım sergilenebilir. Ayrıca Swing dökümanları içerisinde Thread-Safe ifadeleri yer alabilir. Thread-Safe ile işaret edilen durumlar java tarafından sekronize edilmiştir ve aşağıda bahsedeceğim çizim hatalarına neden olmaz.

Bunun asıl sebebi çok kanallı yaklaşımın hem hataları ayıklamayı zorlaştırmaları hemde bazı garip davranışlara yol açması. Bazı sistemler kanalları belirli bir süre çalıştırıp durdururken bazıları ise kanalın kendi isteği ile işlemciyi serbest bırakmasını destekler. Bu iki durumdan bir sakıncası var. Bildiğiniz gibi bir kanal bir iş yaparken yaptığı iş yarıda kesilebilir.  Bu durumda o iş yarıda kalır. Yapılan bu iş sonucu bir çizim yapılacaksa mesela bir düğmenin etiketi çizilecekse o etiket şaçma sapan çizilebiliyor. Çünkü etiketin içeriğini değiştiren kod parçası işini bitiremeden durdurulmuş ve çizim kanalı çalıştırılmıştır. İşte tüm bu ve burada açıklanmayan bazı durumlardan dolayı kullanıcı arayüzünü ilgilendiren bütün işlemler aynı kanalda yapılır. İşte bu kanalın adı EDT dir.

Arayüzü değiştirme işlerinin hepsi EDT içerisinde yapılması gereklidir. EDT için yapılan çağrılar her zaman bir kuyruğa sokulur. Arka arkaya yapılan bir çok çağrı birleştirilip tek sefer de işlenebilir yada sırayla işlenir. İşleri bu şekilde yapamnın bir yararıda kullanıcı arayüzünüzün donmasını engellemektir.

Swing EDT için bazı metotlar sağlar. Bu metotlar:
static void invokeLater(Runnable r)
static void invokeAndWait(Runnable r)
static boolean isEventDispatchThread()
invokeLater Desktop uygulamalarında invokeAndWait Applet uygulamalarında kullanılır. Aslında iki metotda java.awt.EventQueue sınıfındaki metotların tetikleyen cover metotlardır.
invokeLater asenkron olarak çalıştırılırken invokeAndWait senkron olarak çalışır. invokeAndWait illa appletler için kullanılacak diye bir şey yok ancak arayüzü ilk yapılandırırken appletlarda kullanılması önerilmektedir. invokeAndWait AWT kanalı işlem bitene kadar beklemeye alır.

invokeLater'ın önemi uzun hesaplamalar yapacağımız zaman ya da network'e bağlantı yapıp bir veritabanından veri çekeceğimiz zaman ortaya çıkar. Eğer bu işlemleri AWT-Thread (Event Dispatch Thread) içinde yaparsak ve kullanıcı pencereyi ikon durumuna getirip tekrar ekrana büyütürse pencere içerisinin boyanmadığını doğal olarak programın donduğu gibi bir imaj oluştuğunu görürsünüz.

Peki içerisinde bulunduğumuz kanalın AWT kanalı olup olmadığını nasıl anlarız. isEventDispatchThread metodu true gönderirse bu AWT kanalı içerisinde olduğumuzu gösterir. False değeri ise tersini ispatlar.

Swing kütüphanesi tüm bu zorluklardan standart ve kolay bir yöntemle kurtulmamız için SwingWorker adında JavaSE6 (JDK 1.6 / JRE1.6) ile gelen sınıfı bünyesine dahil etmiştir. Ayrıca bu yazının yazıldığı tarih itibari ile terkedilmiş bir çatı olan SAF (Swing Application Framework) Task ile daha iyi çözümler üretmiştir. SAF'ın akıbetinden sonra onun halefi olan  BSAF(Better Swing Application Framework) ortaya çıkmıştır. BSAF'ı google dan aratmanızı tavsiye ederim. Çünkü bu yazı yazılırken kenai üzerinde konumlanan BSAF java.net'e henüz geçmemişti. Swing Worker SAF ve BSAF başka bir yazının konusu. Şimdilik Swing ve EDT konusu bu kadar. Aklıma başka bir şeyler gelirse bu yazıyı güncelleyebilirim yada Swing ve EDT (2) şeklinde başka bir başlıkta yayınlayabilirim.
 
Not: Kenai Oracle kararı ile özellikleri java.net'e aktarılacak ve Oracle'ın kendi içerisinde geliştirilen yazılımlara ev sahipliği yapacak ve son olarak dışarıya kapatılacaktı. Kenai üzerinde konuşlanan yazılım depoları otomatikman java.net'e aktarılacaktı.