thread hilos example java multithreading executors

hilos - Ejecutor de Java con control de estrangulamiento/rendimiento



runnable executorservice example (5)

Estoy buscando un Ejecutor de Java que me permita especificar limitaciones de aceleración / rendimiento / estimulación, por ejemplo, no se pueden procesar más de 100 tareas en un segundo, si se envían más tareas, deberían ponerse en cola y ejecutarse más tarde. El propósito principal de esto es evitar encontrarse con límites al golpear API o servidores externos.

Me pregunto si la base de Java (lo cual dudo, porque verifiqué) o en otro lugar confiable (por ejemplo, Apache Commons) proporciona esto, o si tengo que escribir la mía. Preferiblemente algo ligero. No me importa escribirlo yo mismo, pero si hay una versión "estándar" en algún lugar al menos me gustaría verlo primero.


no se puede procesar más de 100 tareas en un segundo, si se envían más tareas, deben ponerse en cola y ejecutarse más tarde

Debe buscar en Executors.newFixedThreadPool(int limit) . Esto le permitirá limitar el número de subprocesos que se pueden ejecutar simultáneamente. Si envía más de un hilo, se pondrán en cola y se ejecutarán más tarde.

ExecutorService threadPool = Executors.newFixedThreadPool(100); Future<?> result1 = threadPool.submit(runnable1); Future<?> result2 = threadPool.submit(runnable2); Futurte<SomeClass> result3 = threadPool.submit(callable1); ...

El fragmento anterior muestra cómo trabajaría con un ExecutorService que no permite que se ejecuten más de 100 subprocesos simultáneamente.

Actualizar:
Después de revisar los comentarios, esto es lo que he encontrado (algo estúpido). ¿Qué tal mantener manualmente un seguimiento de los hilos que se van a ejecutar? ¿Qué hay de almacenarlos primero en un ArrayList y luego enviarlos al Executor función de la cantidad de subprocesos que se hayan ejecutado en el último segundo?
Entonces, digamos que se han enviado 200 tareas a nuestro ArrayList mantenido, podemos iterar y agregar 100 al Executor . Cuando pasa un segundo, podemos agregar algunos subprocesos más en función de cuántos se hayan completado en el Executor etc.


Dependiendo del escenario, y como se sugiere en una de las respuestas anteriores, las funcionalidades básicas de un ThreadPoolExecutor pueden hacer el truco.

Pero si la agrupación de subprocesos está compartida por varios clientes y desea acelerar, para restringir el uso de cada uno de ellos, asegurándose de que un cliente no use todos los subprocesos, entonces BoundedExecutor hará el trabajo.

Más detalles se pueden encontrar en el siguiente ejemplo:

http://jcip.net/listings/BoundedExecutor.java


Echa un vistazo a las guayabas RateLimiter :

Un limitador de velocidad. Conceptualmente, un limitador de velocidad distribuye permisos a una velocidad configurable. Cada adquisición () bloquea si es necesario hasta que haya un permiso disponible, y luego lo toma. Una vez adquiridos, los permisos no necesitan ser liberados. Los limitadores de velocidad se utilizan a menudo para restringir la velocidad a la que se accede a algún recurso físico o lógico. Esto contrasta con el Semáforo, que restringe el número de accesos concurrentes en lugar de la velocidad (tenga en cuenta que la concurrencia y la velocidad están estrechamente relacionadas, por ejemplo, consulte la Ley de Little).

Su threadsafe, pero aún @Beta . Podría valer la pena intentarlo de todos modos.

Tendría que ajustar cada llamada al Executor con respecto al limitador de velocidad. Para una solución más limpia, podría crear algún tipo de envoltorio para el Servicio de ExecutorService .

Desde el javadoc:

final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second" void submitTasks(List<Runnable> tasks, Executor executor) { for (Runnable task : tasks) { rateLimiter.acquire(); // may wait executor.execute(task); } }


El Ejecutor de Java no ofrece tal limitación, solo limitación por cantidad de subprocesos, que no es lo que está buscando.

En general, el Ejecutor es el lugar equivocado para limitar tales acciones de todos modos, debe ser en el momento en que el Subproceso intenta llamar al servidor externo. Puede hacer esto, por ejemplo, haciendo que un Semaphore limitante en el que los subprocesos esperen antes de enviar sus solicitudes.

Hilo de llamada:

public void run() { // ... requestLimiter.acquire(); connection.send(); // ... }

Mientras que al mismo tiempo usted programa un subproceso secundario (único) para liberar periódicamente (como cada 60 segundos) los recursos adquiridos:

public void run() { // ... requestLimiter.drainPermits(); // make sure not more than max are released by draining the Semaphore empty requestLimiter.release(MAX_NUM_REQUESTS); // ... }


Personalmente me ha parecido bastante interesante este escenario. En mi caso, quería enfatizar que la fase interesante de la aceleración es la que más consume, como en la clásica teoría concurrente de productores / consumidores. Eso es lo contrario de algunas de las respuestas sugeridas antes. Esto es, no queremos bloquear el subproceso de envío, sino bloquear los subprocesos de consumo basados ​​en una política de velocidad (tareas / segundo). Por lo tanto, incluso si hay tareas listas en la cola, la ejecución / consumo de subprocesos puede bloquear la espera para cumplir con la política de trotaje.

Dicho esto, creo que un buen candidato sería Executors.newScheduledThreadPool (int corePoolSize). De esta manera, necesitaría una cola simple delante del ejecutor (un simple LinkedBlockingQueue sería adecuado), y luego programar una tarea periódica para seleccionar tareas reales de la cola (ScheduledExecutorService.scheduleAtFixedRate). Por lo tanto, no es una solución sencilla, pero debería funcionar lo suficientemente bien si intenta estrangular a los consumidores como se comentó anteriormente.