1. Ana Sayfa
  2. Java
  3. Java ve Asenkron Programlama – Java.util.concurrent.Future – Bölüm 1

Java ve Asenkron Programlama – Java.util.concurrent.Future – Bölüm 1

– Bölüm 1. Bu yazıda Java’nın asenkron programlama desteğini ele almaya çalışacağız, pek tabi konu tek bir yazı ile toparlanamayacak kadar büyük ancak bir yerden başlamak lazım 🙂

java.util.concurrent.Future<T>” Interface’i ile başlayacağız.

Interface’in sağladığı api setini incelemeye başlamadan önce senkron icra (Execution) ve asenkron icra (Execution) arasındaki farkı kısaca özetleyelim;

Senkron İcra

Bir işi, bir komutu, herhangi bir şeyi senkron olarak icra ettiğimizde bir sonraki adıma geçebilmek için halihazırda yapmakta olduğumuz işin bitmesini bekleriz.

Asenkron İcra

Bir işi, komutu asenkron olarak icra ettiğimizde bir sonraki adıma icra edilen komut, iş veya şeyin bitmesini beklemeden devam ederiz.


Resim-1

Senkron icrayı markette kasa sırası beklemek olarak betimlersek (aktif olarak sadece bekleme yaptığımızı varsayıyoruz), asenkron programlamayı bankada numara alıp, bir köşede numaramız gelene kadar cep telefonunda oyun oynamaya benzetebiliriz.

Future<T>

Future<T> Interface’i diğer dillerde “Promise” veya “Delay” kavramının limitli veya ilkel (Crude, basic) bir ifadesi olarak tanımlayabiliriz. Java 5 (1.5) ile gelen bu yapı Java’nın asenkron süreçleri yönetmek için sağladığı çözümün temel yapıtaşıdır. Future aşağıdaki Metod tanımlarını içerir:

boolean Cancel(boolean mayInterruptIfRunning)
T get()
T get(long Timeout, TimeUnit unit)
boolean isCancelled()
boolean isDone()

Metodlar az ve öz olduğu için hepsinin ne işe yaradığını tek tek açıklayalım.

Boolean Cancel(boolean mayInterruptIfRunning)

Çalıştırdığımız Task’ın (Future ile tanımlanmış Task) iptal edilmesini sağlar. Geri dönüş değeri, iptal etme başarılı ise “True” değil ise “False” olacaktır. Bu çağrı aşağıdaki koşullarda başarısız olacaktır (False geri dönecektir).

  • Task daha önce tamamlanmış ise
  • Task daha önce iptal edilmiş ise
  • Task bir sebepten ötürü iptal edilememiş ise

Task halihazırda başlamış ve “Cancel” çağrısı mayInterruptIfRunning bayrağı “True” değeri ile çağrılmış ise Java Task’ı icra eden Thread nesnesini Interrupt edecektir. (Thread’in Interrupt edilmesi Task’ın sonlanmasını garanti etmez, bu kısım oldukça önemli ve örnek kodu icra ederken ayrıca değineceğiz)

V get()

Blocking get() çağrısı Future tamamlanıncaya kadar bekleyecek ve herşey başarılı ise Future tarafından üretilen sonucu dönecektir. Eğer “Future.Cancel()” çağrısı yapılmış ise görevin tamamlanmasına bakmaksızın “java.util.concurrent.CancellationException” atarak Blocking State’den çıkacaktır. Yine benzer şekilde “get()” çağrısını icra ederek blocklanan ve “get()” çağrısının sonlanmasını bekleyen Thread başka bir Thread tarafından Interrupt edilirse, “InterruptedException” atarak Blocking State’den çıkacaktır.

V get(long Timeout, TimeUnit unit)

Yukarıda açıklanan “get()” çağrısına ek olarak bu Metod maksimum bekleme zamanını da parametre olarak alır, Future “Timeout” bekleme süresi içerisinde tamamlanır ise sonucu döner, ancak bu süre içerisinde tamamlanamaz ise “TimeoutException” atar ve Blocking State’den çıkar.

Boolean isCancelled()

Future ile ifade edilen görevin iptal edilip edilmediğini geri döner. Eğer Task “Future.Cancel()” çağrısı ile başarılı bir şekilde iptal edilmiş ise “True” diğer durumlarda “False” dönecektir.

Boolean isDone()

Future ile ifade edilen görevin tamamlanıp tamamlanmadığını geri döner. Tamamlanmış ise “True“, iptal edilmiş veya başka bir sebepten başarısız olmuş ise “False” değerini döner.

Future<T> Örnek Kullanım Senaryoları

Future Interface’inin davranışını ve kullanımını daha detaylı incelemek için farklı senaryoları içeren programlarımızı koşup çıktılarının üzerinden geçerek Future ile ilgili anlayışımızı pekiştirelim.

Örnek projeye https://github.com/rozaydin/FutureDemo linki üzerinden erişebilirsiniz. Ayrıca her senaryo için ilgili GIST’e senaryo altında sağlanan linkten direk erişebilirsiniz.

1. Sonucun “get()” çağrısı ile alınması

Senaryo asenkron bir Future Task oluşturarak bu Task’ın icrasının Main Thread içerisinden Blocking “get()” çağrısı ile başarılı bir şekilde alındığı durumu göstermeyi amaçlamıştır.

GIST: https://gist.github.com/rozaydin/b76b973cd64719410686d5ca64a7853a


Resim-2

Program Çıktısı:

1. calling Future.get() — this method will block

Fibonacci Number is: 832040

Process finished with exit code 0

2. Sonucun get(Timeout) ile alınması

Senaryo Timeout değeri ile Blocking get(Timeout, TimeUnit) çağrısını çağırarak asenkron Task’ın en fazla Timeout süresi kadar bekleyerek sonuç üretmesini bekler. Asenkron Task Timeout süresinden önce işlem sonucunu döner.

GIST: https://gist.github.com/rozaydin/0c639f63a8c1b31a8be0021ece48a8cb


Resim-3

Program Çıktısı

1. calling Future.get() — this method will block

Fibonacci Number is: 832040

Process finished with exit code 0

3. Sonucun get(Timeout) ile alınması – Timeout oluşması

Senaryo Timeout değeri ile Blocking “get(Timeout, TimeUnit)” çağrısını kullanarak asenkron Task’ın en fazla Timeout süresi kadar bekleyerek sonuç üretmesini bekler. Asenkron Task Timeout süresinden önce işlem sonucunu dönemez, icra “TimeoutException” ile sonlanır.

GIST: https://gist.github.com/rozaydin/8477421b40317e4d24a27a28e9e53710


Resim-4

Program Çıktısı

1. calling Future.get() — this method will block

Timeout Execution exception occured! java.util.concurrent.TimeoutException

Process finished with exit code 0

4. Task tamamlandıktan sonra Cancel çağrısı ile iptal edilmesi

Senaryo asenkron Task tamamlandıktan sonra “Cancel()” eder ve “get()” çağrısı ile sonucu almayı dener. Task icrasını tamamladıktan sonra “Cancel()” edildiği için “Cancel()” çağrısı başarısız olur (False döner) ve “get()” çağrısı ile Task’ın ürettiği değer Main Thread tarafından alınır.

GIST: https://gist.github.com/rozaydin/b3c9ca8a93d6aa3450e98eaa52e9326c


Resim-5

Program Çıktısı

Task is completed: True

Task Cancellation status: False

1. calling Future.get() — this method will block

Fibonacci Number is: 5

Process finished with exit code 0

5. Task tamamlanmadan önce Cancel çağrısı ile iptal edilmesi

Senaryo asenkron Task’ı tamamlanmadan önce “Cancel()” eder ve “get()” çağrısı ile sonucu almayı dener. Task icrası tamamlanmadan önce Cancel edildiği için Cancel çağrısı başarılı olur (True döner) ve “get()” çağrısı “CancellationException” üretir.

GIST: https://gist.github.com/rozaydin/8bd1cfe8da919b812cc4ee28f71b5d23


Resim-6

Program Çıktısı

Exception in Thread “main” java.util.concurrent.CancellationException

at java.util.concurrent.FutureTask.report(FutureTask.java:121)

at java.util.concurrent.FutureTask.get(FutureTask.java:192)

at org.tutorial.future.CancelScenario2.execute(CancelScenario2.java:44)

at org.tutorial.future.CancelScenario2.main(CancelScenario2.java:58)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:498)

at com.intellij.rt.Execution.application.AppMain.main(AppMain.java:147)

Task is completed: False

Task Cancellation status: True

1. calling Future.get() — this method will block

Process finished with exit code 1

6. Task tamamlanmadan önce “mayInterruptIfRunning” ile iptal edilmesi

Senaryo asenkron Task tamamlanmadan önce Task’ı “mayInterruptIfRunning” bayrağı “True” değeri ile Cancel eder. “FutureTask.Cancel(True)” daha sonra Main Thread Blocking “get()” çağrısını yapar. Task tamamlanmadan iptal edildiği için “get()” çağrısı “CancellationException” atar, program icrası ilgili Exception Handler’a geçer. Bu senaryoda Task’ı icra etmekte olan Thread Interrupt edilir (mayInterruptIfRunning) ancak Thread Interrupt bayrağını dikkate almadığı için sonlanmaz arka planda çalışmaya devam eder.

GIST: https://gist.github.com/rozaydin/dc7cce6b0cf83f125beb9555e2625ec2


Resim-7

Program Çıktısı

Exception in Thread “main” Task is completed: False

Task Cancellation status: True

1. calling Future.get() — this method will block

Interrupted while calculating! java.lang.InterruptedException: sleep Interrupted

pool-1-Thread-1 computation continues in the limbo!

java.util.concurrent.CancellationException

at java.util.concurrent.FutureTask.report(FutureTask.java:121)

at java.util.concurrent.FutureTask.get(FutureTask.java:192)

at org.tutorial.future.CancelScenario4.execute(CancelScenario4.java:46)

at org.tutorial.future.CancelScenario4.main(CancelScenario4.java:61)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:498)

at com.intellij.rt.Execution.application.AppMain.main(AppMain.java:147)

pool-1-Thread-1 computation continues in the limbo!

pool-1-Thread-1 computation continues in the limbo!

pool-1-Thread-1 computation continues in the limbo!

Process finished with exit code 1

Evet biraz uzun bir yazı oldu ancak, Future Interface’i ve temel api setinin neler yaptığını ayrıntılı olarak örnekleri ile inceleme fırsatı bulduk. Bu temel üzerine, bu Interface’i Extend eden diğer Async yapıları inceleyerek devam edeceğiz.

Programlama kariyerinizde belli bir tecrübe yılını aşmış iseniz Bug’larınızın büyük bir kısmının API’nin davranışını yeterince detaylı bilmemekten kaynaklandığını fark etmişsinizdir. (Test Driven Design 🙂 ve önemi ) API’ye yeterince hakim olmak oldukça önemli, bu ayrıca Seasoned Architect’lerin neden yeni API setlerini kullanmaya karşı çıktıklarını da nispeten açıklıyor. Ancak değişim kaçınılmaz, öğrenmeye devam. Bir diğer yazıda görüşmek üzere.

Bu konuyla ilgili sorularınızı https://forum.mshowto.org linkini kullanarak ulaşacağınız forum sayfamızda sorabilirsiniz.

Referanslar

www.mshowto.org

TAGs : Java ve Asenkron Programlama, Java.util.concurrent.Future, , , , , programing, , ,

Yorum Yap

Yazar Hakkında

Rıdvan Özaydın, lisans eğitimini Karadeniz Teknik Üniversitesi Bilgisayar Mühendisliği bölümünde, yüksek lisans eğitimini ise İstanbul Teknik Üniversitesi Bilgisayar Bilimleri bölümünde tamamlamıştır. Yazılım dünyasına üniversitenin ilk yıllarında aldığı C eğitimi ile başlamış, sektörün önde gelen firmalarında Java teknolojileri üzerine çalışmış, şu anda da Thales’de yazılım mühendisi olarak görev almaktadır.

Yorum Yap