Android Thread Kullanımı

Thread bir processin ayrı çizelgelemeye giren akışına denilmektedir.Bir threadin çizelgeleme durumu aşağıdaki gibi olabilir.

Thread LifeCycle

Bir threadin başlangıcı ve bitişi arasıdanki yaşam ömrünü göstermektedir.Buna göre Running durumunda olan bir thread işlemci üzerinde doğrudan komutları çalıştırıyor durumundadır. Bir çok çizelgeleme algoritması Cpu için (biraz ondan biraz bundan tekniğini) kullandıkları için processin running durumda geçiridiği süre dolduğunda process ready durumuna geçer.

Bir process running durumundayken herhangi bir olayı bekliyor(waiting) durumuna geçebilir.Bu olaylar klavye gibi genel olarak giriş çıkış işlemlerine ilişkin olaylar olabilir.

Olayı beklediği süre boyunca thread bloke duruma geçer.Bu durum aslında threadin waiting durumda olması karşılığıdır.

Thread için olay gerçekleştikten sonra Thread doğrudan runnig durumuna geçemez.Yine waiting konumuna geçerek sırasını beklemeye devam eder.

Bir proceses çalışmaya başladığı zaman ismini ana threadden (main primary thread) alarak çalışmaya başlar.

JAVA'da Thread İşlemleri

JAVA da thread işlemleri için Thread sınıfından türetme yapmak ya da Runnable arayüzünü implemente etmek gerekmektedir.Java da bir thread ilk yaratıldığı zaman default olarak nonDaeomon olarak yaratılmaktadır.Java5'ten sonra executer sınıflar yardımıyla thread havuzları kullanılabilimektedir.

Thread sınıfından türetme yapıldığında run metodu override edilir.Run metodu thread akışının olduğu metoddur fakat bu metod dogrudan çağrılarak işlem yapılmaz.Önce bir thread nesnesi yaratılır sonra start metodu ile çalıştırılmaya başlanır.

App.java

/*--------------------------
    Thread sınıfından türetme yaparak thread yaratma
----------------------------*/
package csd;
public class App 
{
    public static void main(String[] args) 
    {    
        Thread thread = Thread.currentThread();

        System.out.println(thread.getName());
        MyThread mt = new MyThread();

        mt.start();
        System.out.println("Main thread ended");
    }
}

MyThread.java

package csd;

public class MyThread extends Thread
{
    @Override
    public void run()
    {
        try {
            for (int i = 0; i < 10; ++i) {
                System.out.println(i);
                Thread.sleep(2000);
            }    
        }
        catch (InterruptedException ex) {
            //...
        }
    }
}

Diğer bir yöntem Runnable arayüzünü implemente etmekdir.Runnable arayüzünü implemente ettikten sonra Thread sınıfının Runnable paramtreli başlangıç metodu ile thread nesnesi yaratılır ve bu nesne için start metodu çağrılır.

Şüphesiz java 8 ile birlikte gelen lambda ifadeleri kullanırak da Thread işlemleri yapılabilir.

Anonim metod kullanılarak da Runnable arayüzü ile thread yaratılabilir.

/*------------------------------------
    Lambda ifadeleri kullanılarak thread yaratılması
------------------------------------*/
package csd;

public class App {

    public static void main(String[] args) 
    {    
        Runnable r = () -> {
            try {
                for (int i = 0; i < 10; ++i) {
                    System.out.println(i);
                    Thread.sleep(2000);
                }    
            }
            catch (InterruptedException ex) {
                //...
            }
        };
        Thread t = new Thread(r);

        t.start();

        System.out.println("Main thread ended");
    }

}

DAEMON THREADLER

Javada bir thread yaratıldığı zaman arka planda çalışan bir thread durumundadır(non deamon) ve process için o thread bir şekilde sonlandırılmazsa sürekli çalışmaya devam eder. processin ana threadi sonlansa bile non daemon threadler sonlanmaz.

Javada thread implementasyonu bu anlamda işletim sisteminin thread mekanizmasından farklıdır. Şüphesiz java threadleri içinde işletim sisteminin aşağı seviyeli thread mekanizması kullanılmaktadır.

Bir threadi daemon durumda çalıştırmak için start metodu çağrılmadan önce setDaemon isimli bir metodu çağrılmalıdır.Thread başladıktan sonra bu metodu çağırmanın bir anlamı yoktur.

Daemon threadler ait oldukları process içerisinde çalışan hiçbir nondaemon thread kalmamışsa yani tüm nondaemon threadler sonlanmışsa sonlanan threadler denilmektedir.

Her threadin bir ismi vardır. Bu isim istenilse thread nesnesi yaratılırken verilebilir. Bir threadin ismini elde edebilmek için thread sınıfının getName isimli metodu kullanılır.

Threadler aynı heap bölgesini kullanırlar fakat hepsinin stack alanları farklıdır. Main Thread Processin ana threadi nondaemon bir threaddir.

Javada Threadlerin Sonlandırılması

Bir threadi sonladırmak için bir kaç tane yöntem düşünülebilir.

1) Thread daemon olarak çalışmaya başlamıştır ve çalışan hiçbir nondaemon thread kalmamıştır. Bu durumda daemon olan thread sonlanmıştır.

package csd;

public class MyThread extends Thread {
    private int m_n;
    public MyThread(String name, int n)
      {
        super(name);
        m_n = n;
    }


    public MyThread(String name, int n, boolean isDaemon)
    {
        this(name, n);
        this.setDaemon(isDaemon);
    }

    @Override
    public void run()
    {
        try {
            if (m_n % 2 == 0)
                for (int i = 0; i < 5; ++i) {
                    System.out.printf("%s:%d%n", this.getName(), i++);
                    Thread.sleep(2000);
                }
            else {
                int i = 0;

                for (;;) {
                    System.out.printf("%s:%d%n", this.getName(), i++);
                    Thread.sleep(2000);
                }
            }
        }
        catch (InterruptedException ex) {
            //...
        }
    }
}
package csd;

public class App {
    public static void main(String[] args) throws InterruptedException 
    {        
        MyThread t1 = new MyThread("NonDaemon-1", 20);        
        MyThread t2 = new MyThread("NonDaemon-2", 20);

        MyThread t3 = new MyThread("Daemon-1", 21, true);
        MyThread t4 = new MyThread("Daemon-2", 21, true);

        t1.start();
        t2.start();
        t3.start();
        t4.start();

        System.out.println("Main thread ended");        
    }

}

2) Bir thread interrupted isimli bir metodu ile sonlandırılabilir. Fakat bu tam anlamıyla bir sonladırma işlemine denk gelmez. interrupted metodu thread içerisinde akış bir takım metotlar içerisindeyken interruptedException isimli nesnenin throw edilmesini sağlar. Bu durumda programcı bir flag mekanizmasına bakmak durumundadır. Bu işlem thread sınıfının static interrupted isimli metodu ile sağlanabilir. Bu metot interruptedException throw edilmişse true, edilmemişse false değerini döner ve çalıştıktan sonra interrupt bayrağını sıfırlar.

package csd;

public class App {
    public static void main(String[] args) throws InterruptedException 
    {
        Runnable r = ()-> {

            int index = 0;

            while (!Thread.interrupted()) {
                System.out.println(index++);
            }
            System.out.println("Thread dışarıdan sonlandırıldı");        

        };

        Thread t = new Thread(r);

        t.start();

        Thread.sleep(5000);

        t.interrupt();

        System.out.println("Main thread ended");            
    }
}

Interrupt işlemi için eğer thread sınıfından türetme yapılarak türetme yapılmışsa o sınıfın static olmayan isInterrupted metodu ile threadin sonlanıp sonlanmadığına bakılablir. Fakat bu metot interrupt flag'ını sıfırlamaz. Eğer programcı bu flagı reset etmek istiyorsa kendisi bu metodu çağırmalıdır.

package csd;

public class App {
    public static void main(String[] args) throws InterruptedException 
    {
        Thread t = new Thread() {
            @Override
            public void run()
            {
                int index = 0;

                while (!this.isInterrupted()) {
                    System.out.println(index++);                
                }
                System.out.println("Thread dışarıdan sonlandırıldı");
            }
        };    


        t.start();

        Thread.sleep(5000);

        t.interrupt();

        System.out.println("Main thread ended");            
    }
}

Aslında thread sınıfının interrupted metodu o anki çalışan thread nesnesine göre hareket etmektedir ve ona göre sonlandırma yapmaktadır. Basit bir sekronize edilmemiş interrupted metodu aşağıdaki gibi yazılabilir.

public static boolean interrupted()
    {
        Thread t = Thread.currentThread();

        boolean result = false;

        if (t.isInterrupted()) {
            t.interrupt();
            result = true;
        }

        return result;
    }

Anahtar Notlar : Aynı kod blokları içerisinde birden fazla akış oluşursa bu tur bölgelere critical section denir. Bu tip bölgelerde sekronizasyon bir çok uygulamada önemli olabilmektedir. Threadlerin sekronizasyonu konusu geniş bir konudur, burada tamamıyla ele alınmayacaktır.

THREADLERİN BİRBİRİNİ BEKLEMESİ

Bilindiği gibi threadler çalıştırılmaya başlatıldığında hangisinin önce çizelgelemeye gireceğinin garantisi yoktur. Bazı durumlarda Threadlerin birbirini beklemesi gerekebilir. Bu durumda thread sınıfının join isimli metotları kullanılmaktadır. Join metodunun parametresiz versiyonu çağrıldığında çağıran thread çağrılan threadi sonlanana kadar bekler.

package csd;
public class App 
{    
    public static void main(String[] args) throws InterruptedException 
    {
        Thread t = new Thread() {
            @Override
            public void run()
            {
                try {
                    for (int i = 0; i < 5; ++i) {
                        System.out.println(i);
                        Thread.sleep(1000);                        
                    }
                }
                catch (InterruptedException ex) {

                }
            }
        };    

        t.start();
        t.join();
        System.out.println("Main thread ended");                
    }
}

Join metodunun milisaniye parametreli metodu, en fazla geçilen milisaniye kadar beklemektedir.

package csd;

public class App {

    public static void main(String[] args) throws InterruptedException 
    {
        Thread t = new Thread() {
            @Override
            public void run()
            {
                try {
                    for (int i = 0; i < 5; ++i) {
                        System.out.println(i);
                        Thread.sleep(1000);                        
                    }
                }
                catch (InterruptedException ex) {

                }
            }
        };    

        t.start();
        t.join(2000);
        System.out.println("Main thread ended");

    }
}

Aşağıdaki örnekte yaratılan threadler sırasıyla birbirlerini beklemektedirler.

App.java

package csd;

import java.util.ArrayList;
import java.util.List;

public class App {

    public static void main(String[] args) throws InterruptedException 
    {
        List<Thread> threads = new ArrayList<>();

        Thread prevThread = null;

        for (int i = 0; i < 10; ++i) {
            Thread curThread =new MyThread("Thread-" + (i + 1), 3, prevThread);
            threads.add(curThread);
            prevThread = curThread;
        }

        for (Thread t : threads)
            t.start();

    }
}

MyThread.java

package csd;

public class MyThread extends Thread {
    private Thread m_prevThread;
    private int m_n;

    public MyThread(String name, int n, Thread prevThread)
    {
        super(name);        
        m_prevThread = prevThread;
        m_n = n;
    }

    @Override
    public void run()
    {
        try {
            if (m_prevThread != null)
                m_prevThread.join();

            for (int i = 0; i < m_n; ++i) {
                System.out.printf("%s-%d%n", this.getName(), i);
                Thread.sleep(1000);                        
            }

        }
        catch (Exception ex) {

        }
    }
}

ANDROİDDE THREAD İŞLEMLERİ

Android işletim sisteminde diğer işletim sistemlerinde olduğu gibi processin ana threadi bulunmaktadır. Temel olarak java içerisindeki threadler android işletim sistemi içerisinde de kullanılmaktadır. Android işletim sistemi içerisinde threadlerin birbirleriyle haberleşmesi için birden fazla yöntem kullanılmaktadır.

Handler Sınıfı ile Threadlerin Haberleşmesi

Handler sınıfı threadler arası haberleşmede kullanılmaktadır. Bu sınıf android.os paketi içerisinde yer almaktadır. Sınıfın default constructor'ı ile hangi thread içerisinde nesne yaratılmışsa başka bir thread bu nesneyi kullanarak bu threadin mesaj kuyruğuna girebilmektedir.

Handler sınıfının postXXX metotları bulunmaktadır. Bu metotlar ilgili threadin içerisinde başka bir threadin çalıştırılması için kullanılmaktadır.

Handler sınıfının post metodu ile bir thread içerisinde diğer threadlerin kullanımı sağlanır.

Handler sınıfı kullanılarak basit bir sayaç programı aşağıdaki gibi yazılabilir.

[DROPBOX]046-HandlerClass

Toast sınıfı da GUI Thread içerisinde çalışması gereken bir sınıftır.Toast sınıfı içinde aynı Handler kullanılmalıdır.

Handler sınıfı yardımıyla bir Threadden başka bir Threade mesaj da gönderilebilmektedir.

Bir Thread'den başka bir Thread'e mesaj göndermek için Handler sınıfının sendXXX metodları kullanılabilir.

Bu işlem için Handler sınıfının handleMessage isimli metodu override edilir ve bu metod içerisinde artık aynı Thread'de olunur.

HandleMesssage metodu sendXXX metodlarıyla gönderilen mesajları karşılayabilecek yetenektedir.İstenirlirse bu elemanlar bundle ile de gönderilebilir.

SendMessage metodu döngü içerisnde sürekli olarak gödenrilmemelidir.Bunun için farklı yollar seçileblir.

Handler sınıfından türetme yapılarak da aynı işlem gerçekleştirilebilir. Handler sınıfından türetme yapılan sınıfta handleMessage metodu override edilir. Override edilen bu handleMessage metodu handler nesnesinin yaratıldığı thread içinde çalıştırılır. Diğer thread'den handlere sentXXX metotlarıyla mesaj gönderilebilir.

handleMessage metodunun parametresi Message türündendir. bu sınıfın what isimli veri elemanı ayraç olarak kullanılabilir. sentEmptyMessage metoduna geçilen argüman what elemanına atanan değerdir. Tüm bu işlemler handler nesnesini diğer threadle paylaşılmasıyla mümkün olur. Yani programcı bir şekilde handler nesnesini işlevi yapacak arka plan threadle paylaşmalıdır.

CountDownTimer SINIFI

CountDownTimer sınıfı sayaç mekanizmasını kendi oluşturduğu threadle gerçekleştiren özel bir timer mekanizmasıdır. Bu sınıfın en önemli özelliği bu türden nesne yaratıldığı zaman ayrıca bir nesne yaratılması gerekmemektedir.

CountDownTimer sınıfının bir tane constructor'ı vardır.

public CountDownTimer(long millisInFuture, long countDownInterval)

millisInFuture : Metodun birinci parametresi milisaniye cinsinden ne kadar süreyle geri sayımın yapılacağının bilgisidir.

countDownInterval : Metotun ikinci parametresi ne kadar zamanda bir geri sayım işleminin mesajının verileceğini belirtir.

Sınıfın onTick metotu belirlenen aralıkta çağrılan metottur.

Sınıfın onFinish metotu ise belirlenen geri sayım işlemi bittiğinde çağrılan metottur.

Sınıfın cancel metotu ile geri sayım işlemi durdurabilir.

start metoduyla geri sayımı başlatılabilir.

Bu sınıf abstract bir sınıftır. Geri sayım işlemi bu sınıftan türetme yapılarak ve onFinish ve onTick metotları override edilerek kullanılabilir. onTick metotunun parametresi her çağrıldığında kalan milisaniyeyi vermektedir.

CountDownTimer da küçük şaşmalar olabilir. Programcı kodu ona göre yazmalıdır. Bu sınıf ile sürekli çalışan bir timer nesnesi oluşturulamamaktadır.Bu sınıf tamamen geri sayım için düşünülmüş bir sınıftır.

[DROPBOX]47-CountDownTimerClass

AsyncTask< T , K , L > SINIFI

AsyncTask sınıfı asenkron işlemleri kolaylıkla yapabilmek için tasarlanmış bir sınıftır. Bu sınıf üç generic parametreli bir sınıftır ve android.os paketi içerisinde bulunmaktadır.

android.os.AsyncTask<Params,Progress,Result>

Sınıfın birinci generic parametresi doInBackground metotudun elipsis parametresinin türüdür.

Sınıfın ikinci generic parametresi onProgressUpdate metodunun elipsis parametresinin türüdür.

Üçüncü generic parametresi sınıfın onPostExecute metodunun parametresinin türüdür.

Bu sınıf abstract bir sınıftır ve programcı bundan türetme yapmalıdır.

Sınıfın doInBackground abstract metotu AsyncTask başlatıldığında başka bir arka plan threadde çalıştırılacak bir metotdur.

Bu metod sonlandığında sınıfın onPostExecute metotu çağrılır.

Programcı arkaplan akışın herhangi bir anında AsyncTask nesnesini yaratan thread içerisinde çalışmak isterse doInBackground içeresinde publishProgress isimli metotu çağırmalıdır. publishProgress metodu çağrıldıktan sonra sınıfın onProgressUpdate metodu AsyncTask isimli nesnenin yaratıldığu threadde çalıştırılmaktadır.

Sınıfın onPreExecute metotu ile doInBackground çağrılmadan önce AsyncTask nesnesi yaratılmadan önce çağrılan metottur.

Anahtar notlar : Javada generic sınıflar içerisinde void kullanımı için Void isimli bir sınıf da bulunmaktadır.

Asynctask sınıfının execute metodları ile ilgili görev çalışmaya başlatılır.

[Dropbox]048-AsyncTask

OnPostExecute metodu doInBackground metodu çalışmayı bitirdikten sonra doInBackground'un döndürdüğü değer ile çağrılır.

onPostExecute metodu da AsyncTask nesnesinin yaratılıp çalıştırıldığı Thread içerisinde çağrılır.

Her adımda AsyncTask nesnesini yaratan ve çalıştıran Threade mesaj göndermek için PublishProgres isimli metodu çağrılabilir.Bu metod çağrıldıktan sonra AsyncTask nesnesini yaratıp çalıştıran Thread'te onProgresUpdate isimli bir metod çağrılacaktır.Bu metod çağrısından sonra akış tekrar doInBackground'a dönecektir.Bu sebeple üst üste binmesi engellemek için onProgresUpdate metodunun çok uzun işlemler yapması tavsiye edilmez.

[Dropbox]049-LoadingSample

049-LoadingSample Ne yapar?

LoadingActivity, MainActivity'den önce açılır ve 3 saniye bekler. sonra da MainActivity'i çağırır.

Kodda yorum satırıyla belirlenen kod işlemin Threadle yapılışı, aktif kod ise AsyncTask ile yazılmış hali

TickTimer da LoadingActivity'de geri sayım için TickTimer kullanılmıştır.

AsyncTask sınıfının ayrıca onCanceled metodları bulunmaktadır.Bu metodlar cancel işlemi yapıldığında çağrılan metodlardır.Cancel metodu boolean türden bir parametre almaktadır.Bu değer true geçilirse doInBackground metodunun çalıştığı thread için Inteerrupt gönderilecektir.False geçilirse görevin bitmesi gerekecektir.Bu konu ileride detaylı ele alınacaktır. Bu metodun geri dönüş değeri boolean türden işlemin sonucudur.

AsnycTaskla ilgili farklı kaynak link

Timer Sınıfı

Bilindiği gibi CountDownTimer sınıfı belirli bir süre boyunca zamanlama işlemini yapmaktadır.Ve kendi Thread mekanizmasını kullanarak onTick metodu içerisinde gereken işlemleri yapmaktadır.

Timer sınıfı sürekli çalışan bir zamanlayıcı sınıftır.Timer sınıfı aslında javanın standart sınıfları içerisindedir.

Timer sınıfı Java'nın Util paketi içinde belirtilmiştir.Bir Timer nesnesi oluşturmak için 4 constructor kullanıabilir. Her Timer nesnensin kendi Thread mekanizması olduğundan bu constructorlar içerisinde açılacak Threadin deamon ya da nonDeamon olucağına ilikşkin boolean parametre bulunmaktadır.Ayrıca Timer nesnesinin bir ismi de olabilmektedir.Ve bu Timer nesnesinin ismi yine başlangıç metodları yardımıyla verilebilmektedir.Sınıfın default başlangıç metodu isimsiz nonDeamon bir thread oluşturacak şekilde bir timer nesnesi yaratmaktadır.

Sınıfın cancel metoduyla çalışan Timer iptal edilebilir.Sınıfın ScheduleXXX metodlarıyla Timer nesnesinin ne zaman başlayacağı , ne gibi bir görev yapacağı gibi bilgiler bildirilebilmektedir.

Sınıfın ScheduleXXX metodları TimerTask isimli bir abstract sınıfı kullanmaktadır.Bu sınıfın abstract run metodu Timer'a verilecek göreve ilişkin kodu belirlemektedir.

Öyleyse programcı TimerTask sınıfından bir türetme yaparak run metodunu implemente eder.TimerTask abstract sınıfı bir arayüz olmadığı için Lambda ifadeleri bu sınıf için kullanılamaz.

Burada Timer sınıfı ayrı bir Thread olduğu için Threadler arası haberleşmeye dikkat edilmelidir.

Schedule yöntemiyle basit bir Timer şöyle programlanabiliir.

//    Timer sınıfı
package kaya.projects;

import java.util.Timer;
import java.util.TimerTask;

public class App {    
    public static void main(String[] args) 
    {
        Timer timer = new Timer("MyTimer");

        TimerTask task = new TimerTask() {
            private int m_count;

            @Override
            public void run()
            {
                System.out.println(++m_count);
            }
        };
        timer.schedule(task, 0, 1000);
    }
}

public void schedule(TimerTask task , long delay , long period)

Sınıfının Schedule metoduyla Timer başlatıldığında verilen periyod kadar ve delay zaman sonra başlamak için tasarlanmıştır.

public void scheduleAtFixedRate(TimerTask task , long delay , long period)

schedule ve scheduleAtFixedRate metodları birbirine benzerdir.scheduleAtFixedRate , schedule göre daha performansı yüksek fakat daha az hassastır.

Timer sınıfında çalışan Thread android içerisinde başka bir Thredle haberleştirilirse etkin olarak kullanılabilir.

[DROPBOX]050-TimerClass

Yaratılmış olan bir Timer nesnesinin Taskını değiştirmek problem oluşturabilmektedir.Bu durumda programcı için en iyi çözüm Timer nesnesini tekrar yaratmaktır.

Timer cancel edildikten sonra aynı task tekrar kullanılmaz durumdadır.Dolayısıyla Timer nesnesinin tekrar yaratılması gereklidir.

Thread Havuzları ve Executer Sınıfları

Java5 ile birlikte ismine Executers denilen diğer bir Thread oluşturmayı sağlayan bir mekanizma eklenmiştir.Bu mekanizma aslında bir Thread havuzu içerisinde istenilen sayıda dinamik ya da statik olarak Thread seçimini sağlamaktadır.Bu mekanizma performansı arttırmak için düşünülmüştür.Andriod sitemlerinde de kolaylıkla uygulanabilmektedir.Bu yöntemle birlikte Callable ve Future isimli iki Arayüz daha kütüphaneye eklenmiştir.Performans açısından iyi olsa da halen programcılar bu yöntemi çok fazla kullanmamaktadır.

Özellikle bir uygulamada belirli bir anda çok fazla Thread yaratılıyorsa performans açısından tercih edilmelidir.

Basit bir Thread havuzu yaratmak için Executers sınıfının newCacheThreadPool ve newFixThreadPool metodlarını kullanabilir.Bu metodların geri dönüş değeri ExecutersService türünden bir arayüz referansıdır.ExecutersService arayüzünün submit isimli metodlarıyla ister Calllable arayüzünü implemente etmiş bir thread, ister Runnable arayüzünü implemente etmiş sınıflar Thread olarak kullanılabilir.

Bu metodlar ExecuterService isimli bir sınıf döndürmektedir. ExecuterService sınıfı havuzu olusturan sınıfın kendisidir.Bu havuzdan bir Thread alabilmek için submit isimli metodlar kullanılabilir.submit metodlarının Callable< T > parametreli versiyonu Callable arayuzunden türetilmiş bir sınıf için kullanılmaktadır.Bu arayüzün call metodu submit işleminden sonra çalışacak Threadin akışını temsil eder.

Submit metodları Future arayüz referansı verir.Future arayüzü ile Thread hakkındaki durumu ve birtakım işlemlerin yönetimi sağlanabilir.

Future Arayüzünün get metodları submit edilen Thread'i beklemek ve call metodunun geri dönüş değerini elde etmek için kullanılabilir.

package kaya.projects;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class App {    
    public static void main(String[] args) throws InterruptedException, ExecutionException
    {
        ExecutorService threadPool =  Executors.newCachedThreadPool();

        Future<?> future = threadPool.submit(new MyCallable(10, 20));

        try {
            int result = (int)future.get(20, TimeUnit.SECONDS);

            System.out.println(result);
        }
        catch (TimeoutException ex) {
            System.out.println("Thread in bekleme süresi doldu");
        }

        threadPool.shutdown();        
    }
}

class MyCallable implements Callable<Integer> {
    private int m_min, m_max;
    public MyCallable(int min, int max) 
    {
        if (min > max)
            throw new IllegalArgumentException("min must be less or equal than max");
        m_min = min;
        m_max = max;
    }
    @Override
    public Integer call()
    {
        int sum = 0;

        for (int i = m_min; i <= m_max; ++i) {
            sum += i;
            System.out.println(i);
            try {
                Thread.sleep(200);
            } 
            catch (InterruptedException e) {

                e.printStackTrace();
            }
        }

        return sum;        
    }
}

Aynı Örnek Anonim metodlarla da yapılabilir.

package kaya.projects;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class App {    
    public static void main(String[] args) throws InterruptedException, ExecutionException
    {
        ExecutorService threadPool =  Executors.newCachedThreadPool();

        final int min = 10, max = 20;

        Future<?> future = threadPool.submit(new Callable<Integer>() {
            @Override
            public Integer call()
            {
                int sum = 0;

                for (int i = min; i <= max; ++i) {
                    sum += i;
                    System.out.println(i);
                    try {
                        Thread.sleep(200);
                    } 
                    catch (InterruptedException e) {

                        e.printStackTrace();
                    }
                }

                return sum;        
            }
        });

        try {
            int result = (int)future.get(20, TimeUnit.SECONDS);

            System.out.println(result);
        }
        catch (TimeoutException ex) {
            System.out.println("Thread in bekleme süresi doldu");
        }

        threadPool.shutdown();        
    }
}

Future sınıfının parametresiz get metodu Thread sonlanana kadar beklemekte kullanılmaktadır.get metodunun timeout ve unit parametreli metodu ise en fazla ne kadar bekleyeceğine dair bilgileri alır.

get(long timeout, TimeUnit unit)
/*
TimeUnit.SECONDS
TimeUnit.MINUTE
TimeUnit.HOUR
TimeUnit.DAY
...
package kaya.projects;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class App {    
    public static void main(String[] args) throws InterruptedException, ExecutionException
    {
        ExecutorService threadPool =  Executors.newCachedThreadPool();

        final int min = 10, max = 20;

        Future<?> future = threadPool.submit(new Callable<Integer>() {
            @Override
            public Integer call()
            {
                int sum = 0;

                for (int i = min; i <= max; ++i) {
                    sum += i;
                    System.out.println(i);
                    try {
                        Thread.sleep(200);
                    } 
                    catch (InterruptedException e) {                        
                        e.printStackTrace();
                    }
                }

                return sum;
            }
        });

        int result = (int)future.get();

        System.out.println(result);


        threadPool.shutdown();        
    }
}

[DROPBOX]051-Executers

[DROPBOX]052-QuestionCompetition