30 Mart 2021 Salı

Thread Sınıfı ve Uncaught Exception

Giriş 
Bence uncaught exceptionlar ile uğraşmak yerine, thread döngüsü içinde şöyle yapmak çok daha kolay.

Örnek
Şöyle yaparız
Thread t = new Thread(new Runnable(){
  @Override
  public void run(){
    while(...){
      try{
        ...
      }catch(InterruptedException ex){
        // you'll need to decide whether to ignore or not thread's interruption
        // This example is in case you decide not to ignore it
        ...
      }catch(Exception ex){
        logError(ex);
      } 
    } //while 
 } //run
});

t.start();
Neden Gerekir ?
Bir bir thread eğer unchecked exception'ı yakalamamışsa, Thread.UncaughtExceptionHandler arayüzünden kalıtan bir metod çalıştırılabilir.

Açıklaması şöyle
When a checked exception is thrown inside the run() method of a Thread object, we have to catch and treat it accordingly, because the run() method doesn’t accept a throws clause. But when an unchecked exception is thrown inside the run() method of a Thread object, the default behavior is to write the stack trace in the console (or log it inside the error log file) and exit the program.

However, with UncaughtExceptionHandler interface, Java provides us with a mechanism to catch and treat the unchecked exceptions thrown in a Thread object to avoid the program’s ending abruptly.
Açıklaması şöyle
So basically when a thread such as the main thread is about to terminate due to an uncaught exception the virtual machine will invoke the thread’s UncaughtExceptionHandler for a chance to perform some error handling like logging the exception to a file or uploading the log to the server before it gets killed.
İşleyiş sırası şöyle
1. Eğer Thread'e setUncaughtExceptionHandler() atanmışsa tetiklenir.
2. Eğer atanmamışsa, thread'in bağlı olduğu ThreadGroup'a setUncaughtExceptionHandler() atanmışsa tetiklenir. Açıklaması şöyle
Every Thread is a member of a ThreadGroup and if the terminated thread doesn’t have an explicitly set handler than it will forward to the thread group handler. If the thread group doesn’t hold any special handler for such cases, it will eventually call it’s default uncaught exception handler.
3. Eğer hiç biri yoksa default uncaught exception handler tetiklenir

setDefaultUncaughtExceptionHandler metodu
Örnek
Şöyle yaparız
Thread.setDefaultUncaughtExceptionHandler(...);
setUncaughtExceptionHandler metodu
Bu metod ile setDefaultUncaughtExceptionHandler() farklı çünkü diğeri static yani tüm thread'ler için geçerli. 
Örnek - thread'i tekrar çalıştırmak
Açıklaması şöyle
When an exception occurs and call reaches the uncaughtExceptionHandler, the state of the thread is Invalid to start again. So you need to create a new thread and start again.
Elimizde şöyle bir kod olsun. Dolayısıyla bu kod hatalı
thread.setUncaughtExceptionHandler((t, e) -> t.run());
Şöyle yaparız
static AtomicInteger counter = new AtomicInteger();

class MyExceptionHandler implements UncaughtExceptionHandler {
  @Override
  public void uncaughtException(Thread t, Throwable e) {
    
    if (counter.get() == 3) {
      System.out.println("Reached Max. retries, exiting");
    } else {
      counter.incrementAndGet();
      new Thread(new MyTask()).start();
    }
  }
}

class MyTask implements Runnable {
  @Override
  public void run() {
    Thread.currentThread().setUncaughtExceptionHandler(new MyExceptionHandler());
    ...
  }
}
Örnek
Thread dursun istiyorsak şöyle yaparız.
Thread thread = ...;

Thread.UncaughtExceptionHandler h = (t, exception) -> {
  t.interrupt();
};
thread.setUncaughtExceptionHandler(h);

25 Mart 2021 Perşembe

ScheduledExecutorService Arayüzü Single Shot Timer Metodları

Giriş
schedule() metodu ile delay verme imkanı var.
submit() metodu ile delay 0 kabul edilir.
 
schedule metodu - Callable
İmzası şöyle.
@Override
public < V > ScheduledFuture< V > schedule(final Callable< V > callable,final long delay,
  final TimeUnit unit);
Örnek
Şöyle yaparız
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
//run the task after 1 second ScheduledFuture<String> future = service.schedule(() -> "Hello",1,TimeUnit.SECONDS); //blocks until the thread has completed and returned result String retVal = future.get(); System.out.println(retVal); service.shutdown();
schedule metodu - Runnable + delay + TimeUnit
İmzası şöyle.
@Override
public ScheduledFuture< ? > schedule(final Runnable command,final long delay,
      final TimeUnit unit);
Belirtilen süre sonra işi çalıştırır. 

Örnek
Şöyle yaparız.  Bu metod servis'in kendi thread'i içinden çağrılmamalı.
final long millis = ...;
service.schedule(() -> {
  ...
  }, millis, TimeUnit.MILLISECONDS);
Örnek
Şöyle yaparız
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
//Run a task after a delay of 1 second
service.schedule(() -> System.out.println("Hello"), 1, TimeUnit.SECONDS);
service.shutdown();
submit metodu - Runnable
İmzası şöyle.
@Override
public Future< ? > submit( final Runnable task );
Bu metod klasik bir Executor gibi kuyruğa girer ve bir ara çalıştırılır.
ScheduledExecutorService dataTimer = Executors.newScheduledThreadPool(1);

if(isDynamic)
{
  dataTimer.scheduleAtFixedRate(myRunnable, 0L, 1000, TimeUnit.MILLISECONDS);
}
else
{
  dataTimer.submit(r);
}
submit metodu - Runnable + Result
İmzası şöyle.
@Override
public < T > Future< T > submit(final Runnable task,final T result);

ScheduledThreadPoolExecutor ve İşin İptali

Giriş
Açıklaması şöyle. Dolayısıyla işi iptal edecekseki kuyruktan silinmesi için setRemoveOnCancelPolicy(true) şeklinde çağırmak gerekir.
ScheduledThreadPoolExecutor maintains an internal work queue of submitted tasks. If a task is cancelled, it does not remove the task from the queue. So it maintains the reference to task.
Örnek
Şöyle yaparız. Böylece future nesnesi ile bu işi durdurmak mümkün olur.
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.setRemoveOnCancelPolicy(true);

ScheduledFuture<?> future = executor.scheduleAtFixedRate(() -> {
  ...
}, 1, 2, TimeUnit.SECONDS);
Örnek
Elimizde şöyle bir kod olsun. Bu kod hatalı, çünkü ScheduledFuture nesnesinin cancel() metodu çağrılsa bile aslında ScheduledExecutorService nesnesnin kuyruğundan silinmiyor.
public class UserMessageCache {

  ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
  ScheduledFuture<?> scheduledFuture;

  public UserMessageCache() {
    // Setup a cleaning job
    ScheduledFuture<?> scheduledFuture = executor.scheduleWithFixedDelay(() -> {
      this.evictExpired();
      }, 20, 20, TimeUnit.SECONDS);
    }
   
    // Evict all expired messages from the cache
    public void evictExpired() {
      ...
    }

    // Purge entire cache and free resources
    public void purge() {
      ...
      scheduledFuture.cancel(false);
  }
}

ScheduledExecutorService Arayüzü Periodic Timer Metodları

Giriş
İki tane metod var. Bunlar
scheduleWithFixedDelay() - İş bitmese bile yeni timer başlar
scheduleAtFixedRate() - İş bitince yeni timer başlar.
Farklılığın açıklaması şöyle
The scheduleAtFixedRate() method creates a new task and submits it to the executor every period, regardless of whether or not the previous task finished.

On the other hand, the scheduleWithFixedDelay() method creates a new task after the previous task has finished.
Yani scheduleWithFixedRate() yeni işi tam saatinde başlatır. Her saat başı kahve yapan işin çıktısı şöyle.  İş 10 dakika sürüyor. Bir sonraki iş ileri kaymadı
00:00: Start making coffee
00:10: Finish making coffee
01:00: Start making coffee
01:10: Finish making coffee
02:00: Start making coffee
02:10: Finish making coffee
Yani scheduleWithFixedDelay() yeni işi bir önceki işe göre başlatır. Çıktısı şöyle. İş 10 dakika sürüyor. Bir sonraki iş te 10 dakika ileri kaydı.
00:00: Start making coffee
00:10: Finish making coffee
01:10: Start making coffee
01:20: Finish making coffee
02:20: Start making coffee
02:30: Finish making coffee



scheduleWithFixedDelay metodu - Runnable
İmzası şöyle.
@Override
public ScheduledFuture< ? > scheduleWithFixedDelay(final Runnable command,
  final long initialDelay,final long delay,final TimeUnit unit);
Bu metod bir sonraki timer zamanını Runnable bittikten sonra kurar.
Örnek
Şöyle yaparız.
scheduledExecutorService.scheduleWithFixedDelay (foo, 1, 1, TimeUnit.NANOSECONDS);

scheduleAtFixedRate metodu - Runnable
İmzası şöyle.
@Override
public ScheduledFuture< ? > scheduleAtFixedRate(final Runnable command,
  final long initialDelay, final long period,final TimeUnit unit);
İlk parametre Runnable arayüzünden kalıtan bir nesnedir.
İkinci parametre delay yani gecikmedir.
Üçüncü parametre süredir 
Dördüncü parametre ise sürenin birimini belirtir.

Örnek
Mesela her dakika bir çalışması istenen iş şöyle yaratılır.
ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
exec.scheduleAtFixedRate(myRunnable , 0, 1, TimeUnit.MINUTES);
Örnek
Her saniye bir çalışması istenen iş şöyle yaratılır.
es.scheduleAtFixedRate(myRunnable, 0, 1, TimeUnit.SECONDS);
Örnek
Milisaniye seviyesinde çalışması istenen iş şöyle yaratılır.
es.scheduleAtFixedRate(myRunnable, 0L, 500, TimeUnit.MILLISECONDS);