En basit Executer bir Runnable'ı doğrudan çalıştıran Executer'dırEn 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
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.
Verilen Runnable'ları sırayla çalıştıran Executer örneğiVerilen 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.
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
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.
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
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ı.