java - example - Thread.sleep() VS Executor.scheduleWithFixedDelay()
scheduledexecutorservice java 8 (4)
Como no has mencionado la versión de Java, entonces, las cosas podrían cambiar.
Como recuerdo del código fuente de Java, la principal diferencia que viene es la forma en que las cosas se escriben internamente.
Para Sun Java 1.6, si utiliza el segundo enfoque, el código nativo también provoca la espera y notifica las llamadas al sistema. Por lo tanto, de una manera más eficiente en subprocesos y compatible con la CPU.
Pero nuevamente, pierde el control y se vuelve más impredecible para su código: considere que quiere dormir durante 10 segundos.
Entonces, si desea más previsibilidad, seguramente puede optar por la opción 1.
Además, en una nota al margen, en los sistemas heredados cuando encuentras cosas como esta (80% de posibilidades, ahora hay mejores formas de hacerlo), pero los números mágicos están ahí por una razón (el 20% restante), entonces, cámbiala en propio riesgo :)
Objetivo: Ejecutar cierto código de vez en cuando.
Pregunta: En términos de rendimiento, ¿hay una diferencia significativa entre:
while(true) {
execute();
Thread.sleep(10 * 1000);
}
y
executor.scheduleWithFixedDelay(runnableWithoutSleep, 0, 10, TimeUnit.SECONDS);
?
Por supuesto, la última opción es más kosher. Sin embargo, me gustaría saber si debo embarcarme en una aventura llamada "Pase unos días refactorizando el código heredado para despedir a Thread.sleep ()".
Actualización: este código se ejecuta en un entorno de carga súper / mega / hiper.
Estás tratando con tiempos de sueño en decenas de segundos. Los posibles ahorros al cambiar la opción de suspensión aquí son probablemente nanosegundos o microsegundos.
Prefiero el último estilo cada vez, pero si tiene el primero y le costará mucho cambiarlo, "mejorar el rendimiento" no es una justificación particularmente buena.
EDITAR re: 8000 hilos
8000 hilos es una gran cantidad; Podría pasar al ejecutor programado solo para que pueda controlar la cantidad de carga que se coloca en su sistema. Debes tener en cuenta tu punto sobre los diferentes tiempos de activación, aunque diría que el mayor riesgo es una estampida de hilos durmiendo y luego despertando en una sucesión cercana y compitiendo por todos los recursos del sistema.
Pasaría el tiempo para lanzar todo esto en un ejecutor programado de grupo de subprocesos fijos. Solo tenga la cantidad de ejecución simultánea que tenga disponible del recurso más limitado (por ejemplo, # cores, o # rutas IO) más unos pocos para eliminar cualquier pendiente. Esto le dará un buen rendimiento a expensas de la latencia.
Con el método Thread.sleep()
será muy difícil controlar lo que está sucediendo, y es probable que pierda tanto el rendimiento como la latencia.
Si necesita consejos más detallados, probablemente tendrá que describir lo que está tratando de hacer con más detalle.
Hay diferentes escenarios,
- El temporizador crea una cola de tareas que se actualiza continuamente. Cuando se termina el temporizador, no se puede recoger la basura inmediatamente. Así que crear más temporizadores solo agrega más objetos al montón. Thread.sleep () solo detiene el subproceso, por lo que la sobrecarga de memoria sería extremadamente baja
- Timer / TimerTask también tiene en cuenta el tiempo de ejecución de su tarea, por lo que será un poco más preciso. Y se trata mejor con problemas de subprocesos múltiples (como evitar puntos muertos, etc.).
- Si subprocesas obtener una excepción y te matan, eso es un problema. Pero TimerTask se encargará de ello. Se ejecutará independientemente de la falla en la ejecución anterior
- La ventaja de TimerTask es que expresa su intención mucho mejor (es decir, la legibilidad del código), y ya tiene implementada la función cancel ().
La referencia se toma de here
Usted dijo que se está ejecutando en un "mega ... entorno de alta carga", por lo que si lo comprendo correctamente, tiene muchos subprocesos al mismo tiempo durmiendo como su ejemplo de código. Se necesita menos tiempo de CPU para reutilizar un hilo que para matar y crear uno nuevo, y la refactorización puede permitirle reutilizar hilos.
Puede crear un grupo de subprocesos utilizando un ScheduledThreadPoolExecutor con un corePoolSize
mayor que 1. Luego, cuando llame a scheduleWithFixedDelay en ese grupo de subprocesos, si hay un subproceso disponible, se reutilizará.
Este cambio puede reducir la utilización de la CPU, ya que los subprocesos se reutilizan en lugar de destruirse y crearse, pero el grado de reducción dependerá de las tareas que estén realizando, del número de subprocesos en el grupo, etc. El uso de la memoria también disminuirá si algunos de las tareas se superponen, ya que habrá menos subprocesos inactivos a la vez.