ExecutorService unter Java nutzen

Wenn unter Java die Ausführung von Quelltext parallelisiert werden soll, so können hierfür Threads genutzt werden:

Thread thread = new Thread(new TestRunnable());
thread.start();

In diesem Beispiel wird für eine auszuführende Aufgabe ein Thread erstellt und dieser anschließend gestartet. Nun kann es Fälle geben, in welchem mehrere Threads die gleiche Aufgabe ausführen sollen, allerdings nicht unbedingt die entsprechende Anzahl von Threads angelegt werden soll. Für eine solche Aufgabe eignet sich ein ExecutorService. Im ersten Schritt sollte ein Runnable definiert werden. In diesem Interface wird eine run-Methode definiert, die den auszuführenden Quellcode enthält:

public static class TestRunnable implements Runnable {

    @Override
    public void run() {
        // Do something
    }
}

Nun kann der ExecutorService angelegt werden und mit einem Threadpool ausgestattet werden. Anschließend werden die neuen Instanzen des Runnable, mittels der execute-Methode, an den ExecutorService übergeben.

// Executor service
ExecutorService executorService = Executors.newCachedThreadPool();

// Add jobs to executor service
for (int i = 0; i < 100; i++) {
    executorService.execute(new TestRunnable());
}

// Shutdown executor service
executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

Damit würden die Aufgaben abgearbeitet. Allerdings würde der ExecutorService nun bis zu einem Timeout noch bestehen bleiben. Stattdessen wird er im Beispiel kontrolliert heruntergefahren. Nach der Ausführung der shutdown-Methode nimmt der ExecutorService keine neuen Aufträge mehr an; bestehende Aufträge werden allerdings noch abgearbeitet. Über die Methode awaitTermination wird sichergestellt das der Service wartet, bis alle Aufgaben abgearbeitet sind. Bei der Methode wird ein Timeout angegeben, nach welchem der Service zwangsweise abgeschaltet wird. Damit werden die Aufgaben Stück für Stück abgearbeitet, ohne entsprechende viele Threads zu öffnen. Stattdessen werden Threads aus dem Threadpool wiederverwendet.

Threadsicheres Dictionary unter .NET

Das Dictionary unter .NET ist eine schöne Datenstruktur mit der man effizient Schlüssel- und Wertepaare verwalten kann:

Dictionary<uint, byte[]> idToValues=new Dictionary<uint, byte[]>();
idToValues.Add(1, data);

Problematisch wird das ganze, sobald in mehreren Threads gearbeitet wird, welche alle auf das gleiche Dictionary zugreifen. Hier müssen die Zugriffe auf das Wörterbuch kontrolliert und entsprechend gesperrt werden. Einfacher wird es mit der 4er .NET Framework. Dort gibt es ein ConcurrentDictionary welches von Haus aus threadsicher ist und dem Entwickler eine Menge Arbeit erspart.

ConcurrentDictionary<uint, byte[]> idToValues=new ConcurrentDictionary<uint, byte[]>();
idToValues.TryAdd(1, data);

Das “ConcurrentDictionary” kann dabei im Großen und Ganzen wie ein normales Dictionary genutzt werden, so das die Umstellung nicht allzu schwer fallen sollte.

Threadsichere Event unter C#

Events unter C# sind so eine Sache. Im Normalfall funktionieren sie ohne Probleme. Spannend wird das ganze wenn man Events in einer Anwendung zwischen verschiedenen Threads verschicken möchte. Dabei kann es nämlich passieren das Events verloren gehen weil sie nicht empfangen werden. Abhilfe schafft hier die Klasse “ThreadSafeEvent”:

public class ThreadSafeEvent
{
  EventHandler internalEventHandler;
  readonly object internalEventHandlerLock=new object();

  public event EventHandler Event
  {
    add
    {
      lock(internalEventHandlerLock)
      {
        internalEventHandler+=value;
      }
    }
    remove
    {
      lock(internalEventHandlerLock)
      {
        internalEventHandler-=value;
      }
    }
  }

  public virtual void Fire(object sender, EventArgs e)
  {
    EventHandler handler;

    lock(internalEventHandlerLock)
    {
      handler=internalEventHandler;
    }

    if(handler!=null)
    {
      handler(sender, e);
    }
  }
}

Möchte man nun z.B. der Klasse “Entries” eine solches Event hinzufügen, so sieht das ganze wie folgt aus:

public ThreadSafeEvent EntrySelected=new ThreadSafeEvent();

Nun kann das Event gefeuert werden, das ganze wird mittels der “Fire” Methode bewerkstelligt. Dieser übergibt man den Sender und zusätzliche Argumente in Form eines “EventArgs” bzw. einer davon abgeleiteten Klasse.

EntrySelected.Fire(this, new EntryEventArgs(entry));

Jede Klasse welche das Event nun empfangen möchte hängt sich an das entsprechende Event.

Entries entries=new Entries();
Entries.EntrySelected.Event+=OnEntrySelected;

...

private void OnEntrySelected(object sender, EventArgs e)
{
  EntryEventArgs args=(EntryEventArgs)e;
  Console.WriteLine(args.Entry);
}

Und schon haben wir in unserer Anwendung ein sauberes und threadsicheres Eventsystem.