İçerikler :

Basit Bir Future ve Callable Örneği Callable Doğrudan Çalıştıran Executer Executor ExecutorService ile Açılan Socket'i İşleylen .. Future java.util.concurrent API newFixedThreadPool ile ExecutorService Yarata.. Runnable ile Callable Farkı ScheduledExecutorService Kullanan Bir Selamla.. Sıralı Olarak Çalıştıran Executer Yeni Bir Thread Açarak Çalıştıran Executer

Bu Sayfayı Paylaş:

Kavram

java.util.concurrent API

Tanım: Standar java içerisinde bulunan, concurrent programming (eşzamanlı programlama) kütüphanesi

Kavram

Executor

Tanım: java.util.concurrent API'sinde, eklenen Runnable sınıfı bir task'ı çalıştırmak için implements edilmesi gereken interface. Sadece execute(Runnable command) methodunu içermektedir. ExecutorService, ScheduledExecutorService alt interface'leri , AbstractExecutorService, ForkJoinPool, ScheduledThreadPoolExecutor, ThreadPoolExecutor gibi implement etmiş sınıfları bulunmaktadır.

Örnek

Doğrudan Çalıştıran Executer

En basit Executer bir Runnable'ı doğrudan çalıştıran Executer'dır
En basit Executer bir Runnable'ı doğrudan çalıştıran Executer'dır:
class DirectExecutor implements Executor {
 public void execute(Runnable r) {
	 r.run();
 }
}

DirectExecutor sınıfı gelen Runnable'ı çalıştırır ve herhangi başka bir şey yapmaz

Örnek

Yeni Bir Thread Açarak Çalıştıran Executer

Her execute işleminde ayrı bir thread açılmasını sağlayan örnek aşağıdaki gibidir :
class ThreadPerTaskExecutor implements Executor {
 public void execute(Runnable r) {
	 new Thread(r).start();
 }
}
ThreadPerTaskExecutor her execute edildiğinde yeni bir thread açmaktadır.

Örnek

Sıralı Olarak Çalıştıran Executer

Verilen Runnable'ları sırayla çalıştıran Executer örneği
Verilen Runnable'ları sırayla çalıştıran Executer örneği aşağıdaki gibidir:
 
class SerialExecutor implements Executor {
   final Queue tasks = new ArrayDeque();
   final Executor executor;
   Runnable active;
   SerialExecutor(Executor executor) {
     this.executor = executor;
   }
   public synchronized void execute(final Runnable r) {
     tasks.offer(new Runnable() {
       public void run() {
         try {
           r.run();
         } finally {
           scheduleNext();
         }
       }
     });
     if (active == null) {
       scheduleNext();
     }
   }
   protected synchronized void scheduleNext() {
     if ((active = tasks.poll()) != null) {
       executor.execute(active);
     }
   }
 }

SerialExecutor sınıfı, tasks kuyruğuna eklenen Runnable'ları sırayla çalıştırmaktadır.

Örnek

ScheduledExecutorService Kullanan Bir Selamlayıcı

1 saat boyunca 10 saniyede bir ekrana merhaba yazacak bir örnek ScheduledExecutorService kullanılarak yapılabilir. Aşağıdaki örnek bu işlevi yerine getirmektedir:
import static java.util.concurrent.TimeUnit.SECONDS;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;

public class Greeting {
	
	private final ScheduledExecutorService scheduler =
			Executors.newScheduledThreadPool(1);

	public void forAnHour() {
		
		final Runnable greeter = new Runnable() {
			public void run() {
				System.out.println("merhaba");
			}
		};
		
		//10 snde bir merhaba yazacak
		final ScheduledFuture<?> greeterHandle =
				scheduler.scheduleAtFixedRate(greeter, 10, 10, SECONDS);
		
		// bir saat sonra sona erdirilecek
		scheduler.schedule(new Runnable() {
			public void run() {
				greeterHandle.cancel(true);
			}
		}, 60 * 60, SECONDS);
		
	}
	
	public static void main(String[] args) {
		
		Greeting greeting=new Greeting();
		greeting.forAnHour();
		
	}
}
Öncelikle greeter adında erkana merhaba yazan bir Runnable yaratıyoruz. scheduleAtFixedRate ile 10 sn'de bir bu Runnable çalıştırılacak şekilde ayarlanmıştır. schedule() yöntemi ile de 1 saat sonra bir task çalışacak ve 10 sn bir çalışan greeterHandle durdurulacaktır. Uygulama çalıştığında 10 sn'de bir merhaba yazısı çıktıda görülecektir:
merhaba
merhaba
merhaba
merhaba
merhaba
merhaba

Örnek

ExecutorService ile Açılan Socket'i İşleylen Bir Örnek

Bu örnekte ExecutorService her yeni bir socket açıldığında isteği ayrı bir Thread yaratarak işleyen bir örnek görülmektedir.Örnek uygulama aşağıdaki gibidir:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NetworkService implements Runnable {

	private final ServerSocket serverSocket;
	private final ExecutorSevrvice pool;

	public NetworkService(int port, int poolSize) throws IOException {
		serverSocket = new ServerSocket(port);
		pool = Executors.newFixedThreadPool(poolSize);
	}

	public void run() { // run the service
		try {
			for (;;) {
				pool.execute(new Handler(serverSocket.accept()));
			}
		} catch (IOException ex) {
			pool.shutdown();
		}
	}

	public static class Handler implements Runnable {
		private final Socket socket;

		Handler(Socket socket) {
			this.socket = socket;
		}

		public void run() {
			System.out.println("socket handler run...");
		}
	}
	
	public static void main(String[] args) throws IOException {
		
		NetworkService networkService=new NetworkService(8081, 10);
		
		System.out.println("Network service running");
		
		networkService.run();

	}

}
NetworkService sınıfınun run yöntemi main'deki gibi çağrıldığında serverSocket.accept() ile yeni bir socket beklenir duruma geçilecektir. 8081 portunu dinlenilmektedir. En fazla 10 thread olacak şekilde bir havuz yaratılmıştır. Bir socket açılırsa Handler'daki kod çalıştırılır ve yeni bir socket beklenir. Test edebilmek için socket açan bir client örneği yapalım:
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class NetworkServiceClient {
	
	public static void main(String[] args) 
			throws UnknownHostException, IOException {
		
		for (int i=0;i<10;i++) {
			Socket socket=new Socket("10.26.12.162", 8081);
		}	
		
	}
}
Döngü açıp 10 tane socket açıyoruz. Her socket'te sunucu tarafında Handler çalıştırılır ve ekrana socket hander run... yazısını yazar:
Network service running
socket handler run...
socket handler run...
socket handler run...
socket handler run...
socket handler run...
socket handler run...
socket handler run...
socket handler run...
socket handler run...
socket handler run...
Eğer 10 thread çalışırken yeni thread'lar eklenirse, önce elindeki 10 thread'i bitirir ve diğer 10 thread'e devam eder. Bu şekilde tüm thread'leri çalıştırır. Bunu anlamak için run yöntemini aşağıdaki çalıştırıp, Thread'leri bekletebiliriz:
public void run() {
	
	try {
		Thread.sleep(10000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	
	System.out.println("socket hander run...");
}
Bu şekilde döngüyü 100'e çekip çalıştırırsak, 10'ar 10'ar mesajların yazılacağını görebilirsiniz.

Örnek

newFixedThreadPool ile ExecutorService Yaratan Bir Örnek

Bu örnekte 10 Thread havuzu olan bir ExecutorService yaratıyoruz. Bu servise 25 ayrı Thread ekliyoruz ve çalıştırıyoruz:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestApp {
		
	public static void main(String[] args) {
		
		ExecutorService executor = Executors.newFixedThreadPool(10);
		
		for (int i = 0; i < 25; i++) {
			 
			Runnable worker = new MyRunnable(i+1);
			executor.execute(worker);
			
		}
		
		executor.shutdown();
		// Thread'lerin sona ermesi beklenir
		while (!executor.isTerminated()) {
			
		}
		
		System.out.println("Uygulama sona erdi");
		
	}
	
	public static class MyRunnable implements Runnable {
		private int index=0;
		
		public MyRunnable(int index) {
			this.index=index;
		}
		
		@Override
		public void run() {
			
			System.out.println(index+".nci thread calisiyor");
			
		    try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		    
		}
		
	}
}
Uygulama önce 10 thread havuzu olan bir ExecutorService servisi yaratılıyor. Havuzun anlamı aynı anda en fazla 10 Thread'in çalışmasıdır. Sonra 25 Thread yaratıp çalıştırıryoruz. Ardından shutdown() ile kapatıyoruz. Ancak executor.isTerminated() ile tüm Thread'lerin çalışmasını tamamlamasını bekliyoruz. Uygulama çalıştığı zaman 25 Thread'i 10ar 10ar işleyecek ve kapanacaktır :
2.nci thread calisiyor
3.nci thread calisiyor
1.nci thread calisiyor
4.nci thread calisiyor
5.nci thread calisiyor
6.nci thread calisiyor
7.nci thread calisiyor
8.nci thread calisiyor
9.nci thread calisiyor
10.nci thread calisiyor
11.nci thread calisiyor
13.nci thread calisiyor
12.nci thread calisiyor
14.nci thread calisiyor
15.nci thread calisiyor
16.nci thread calisiyor
17.nci thread calisiyor
19.nci thread calisiyor
18.nci thread calisiyor
20.nci thread calisiyor
21.nci thread calisiyor
23.nci thread calisiyor
22.nci thread calisiyor
25.nci thread calisiyor
24.nci thread calisiyor
Uygulama sona erdi

Kavram

Callable

Tanım: Bir Thread tarafından çalıştırılabilen ve geri bir sonuç döndüren bir görev yapmak için kullanılan bir interface. V call() throws Exception şeklinde tek bir yöntemi vardır. Runnable'den farklı olarak geri sonuç döner ve exception fırlatabilir.

İpucu

Runnable ile Callable Farkı

Runnuable ve Callable bir görevi farklı bir Thread ile çalıştırmak için kullanılan iki interface'dir.
Runnable'ın run() yöntemi geri bir sonuç döndürmezken, Callable'nın call() yöntemi sonuç döndürür. Ek olarak call() yöntemi Exception oluşturarak işlemden çıkabilir. Runnable'nın run yöntemi exception fırlatamaz.
Callable ile bir Thread yaratılamaz. Thread ancak Runnable ile yaratılabilir. Callable ise ExecutorService sınıfları ile çalıştırılabilir.
Thread Java'nın ilk versiyondan beri olan bir sınıftır. Callable ise 5 ile gelmiştir.
Callable'larden sonucu almak için Future interface'si kullanılır. ExecutorService ile çalıştırılır ve sonuç asenktron olarak Future nesnesi ile alınır.

Kavram

Future

Tanım: Asenkron hesaplamalarda bir thread çalışması oluşan sonucu almak için kullanılan bir interface. Bu interfaces'in ana amacı çalıştırılan bir Thread'den ana Thread'e sonuç aktarılmasıdır. Eğer çalışma sonucu tamamlandı ise get() yöntemi ile sonuç alınır. get() yöntemi ana thread'i çalışma bitene kadar bekletir ve çalışma bittiğinde sonucu alır. cancel() ile de çalışma durdurulabilir.

Örnek

Basit Bir Future ve Callable Örneği

Bu örnekte olabilecek en basit Callable örneği yaratıyoruz. Sadece sonuç olarak bir String döndürüyor.
import java.util.concurrent.*;
public class Test {	
	public static void main(String[] args) {		
		ExecutorService executorService=Executors.newSingleThreadExecutor();		
		Future<String> future = executorService.submit(
			new Callable<String>() {
				public String call() {	            	        	
					return "OK";	        	 
				}
			}
		);	
		try {
			System.out.println(future.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}		
		executorService.shutdown();
	}
}
İlk işlem olarak tel Thread'li bir ExecutorService yaratıyoruz. Ona çalıştırmak için bir Callable veriyoruz. Yaratılan Callable sadece String sonucu döndürüyor. ExecutorService'in submit() yöntemi geriye Future döndürüyor. Daha sonra get() yonteminde ana Thread sonucu bekler. Sonuç geldiğinde ise sonuç ekrana basılır. Son satırla da ExecutorService shotdown edilir. aksi takdirde uygulama sürekli ayakta kalırdı.



Bu Sayfayı Paylaş:

İletişim Bilgileri

Takip Et

Her Hakkı Saklıdır. Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir. Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir