2016-07-24 4 views
4

Ich suche nach einer Möglichkeit, die Anzahl der Threads zu begrenzen, die einen bestimmten Codeabschnitt in Java mit Semaphoren oder ähnlichem ausführen können.Der beste Weg, um die Anzahl der Threads zu begrenzen, die einen bestimmten Codeabschnitt in Java ausführen?

Wir suchten nach etwas Ähnliches wie Google Guava RateLimiter - aber anstatt die Anzahl der Aufrufe pro Sekunde zu begrenzen, müssen wir die Anzahl der Threads begrenzen, um den kritischen Codeabschnitt auszuführen.

Der Grund, warum dies erforderlich ist, ist, dass bestimmte Bibliothek, die wir verwenden, hier Probleme hat, so dass wir nur nach einer schnellen Abhilfe suchen.

+1

Warum können Sie java.util.concurrent.Semaphore nicht verwenden? –

Antwort

4

Das ist genau das, was java.util.concurrent.Semaphore entworfen wurde, zu tun. Sie erstellen ein Semaphore wie so:

final int MAX_NOF_THREADS = 5; 
final Semaphore mySemaphore = new Semaphore(MAX_NOF_THREADS); 

dann für den kritischen Bereich, den Sie tun würde:

try { 
    mySemaphore.aquire(); // This will hang until there is a vacancy 
    do_my_critical_stuff(); 
} finally { 
    mySemaphore.release(); 
} 

... so einfach ist das.

+1

Ich stimme völlig zu "Semaphore's, sie sollten die erste Wahl für diese Aufgabe sein. Eines ist jedoch erwähnenswert: Technisch gesehen darf ein Thread mehrere Acquiring-Vorgänge durchführen. Das bedeutet, dass einige logische Fehler (z. B. eine falsch konzipierte Rekursion) zu einer Unterauslastung von Threads oder sogar zu einem Deadlock führen können. Aber wenn sie vorsichtig verwendet werden, sind sie das richtige Werkzeug hier. –

4

Obwohl, Semaphore ist die beste Wahl hier (siehe die Antwort von @ Bex), wenn Sie vorsichtig sind, ist es auch möglich, ExecutorService zu verwenden. wickeln Sie einfach das Stück Code, das Sie möchten aus unbegrenzte Anzahl gleichzeitiger Zugang zu einer Callable Aufgabe schützen und solche Aufgaben an den Testamentsvollstrecker Dienst einreichen:

// Task that will be executed 
public class MyTask implements Callable<Void> { 
    @Override 
    public Void call() { 
     // Do the work here 
     return null; 
    } 
} 

// Service to execute tasks in no more than 5 parallel threads 
// Cache it after creation and use when you need to execute a task 
int maxThreadsCount = 5; 
ExecutorService executor = Executors.newFixedThreadPool(maxThreadsCount); 

// Execute a task. It will wait if all 5 threads are busy right now. 
executor.submit(new MyTask()); 

Mit ExecutorService Sie auch Runnable statt Callable, invokeAll() verwenden können, statt execute, warten Sie auf den Abschluss der Aufgabe, brechen Sie Aufgaben ab, geben Sie Werte von ihnen zurück und machen Sie andere nützliche Dinge.

Java 8 macht es einfacher, können Sie lambdas verwenden stattdessen Aufgabenklassen definieren:

executor.submit(() -> { 
    // Do the work here 
}); 
+1

Zu beachten ist, dass die Executors-Factory ExecutorService-Implementierungen erstellt, die von unbeschränkten Jobwarteschlangen unterstützt werden. Je nach Häufigkeit und Dauer der laufenden Jobs kann sich dies negativ auf das System auswirken. In einigen Fällen kann es aufgrund der Anzahl der im Speicher eingereihten Jobs zu Problemen kommen. In diesen Fällen kann es sich lohnen, einen eigenen ** ThreadPoolExecutor ** mit einer begrenzten Arbeitswarteschlange und einem benutzerdefinierten ** RejectedExecutionHandler ** zu erstellen. Da der Codeabschnitt kritisch ist, möchten Sie wahrscheinlich die unbegrenzte Version. Seien Sie sich der Auswirkungen bewusst. – Jeremiah

Verwandte Themen