threads thread objetos metodos metodo hilos ejemplo declaracion creacion controlar java memory multithreading cpu throttling

objetos - runnable thread java



¿Limitar el uso de CPU/memoria de un subproceso en Java? (9)

¿Por qué no en lugar de hacer "threading" hacer multitarea cooperativa, sería interesante ver si puede manipular http://www.janino.net/ para ejecutar un programa por una cierta cantidad de tiempo / conjunto de instrucciones, luego detener y ejecutar el próximo programa Al menos de esa manera es justo, dales a todos el mismo segmento de tiempo ...

Estoy escribiendo una aplicación que tendrá varios subprocesos en ejecución, y quiero acelerar el uso de CPU / memoria de esos subprocesos.

Hay una pregunta similar para C ++ , pero quiero intentar y evitar el uso de C ++ y JNI si es posible. Me doy cuenta de que esto podría no ser posible utilizando un lenguaje de nivel superior, pero tengo curiosidad por ver si alguien tiene alguna idea.

EDITAR: Agregó una recompensa; Me gustaría algunas ideas realmente buenas y bien pensadas sobre esto.

EDIT 2: La situación que necesito para esto es ejecutar el código de otras personas en mi servidor. Básicamente es un código completamente arbitrario, con la única garantía de que habrá un método principal en el archivo de clase. Actualmente, varias clases completamente dispares, que se cargan en tiempo de ejecución, se ejecutan simultáneamente como subprocesos separados.

De la forma en que está escrito, sería un gran esfuerzo refactorizar para crear procesos separados para cada clase que se ejecuta. Si esa es la única buena forma de limitar el uso de la memoria a través de los argumentos de VM, entonces que así sea. Pero me gustaría saber si hay una manera de hacerlo con hilos. Incluso como un proceso separado, me gustaría poder limitar de alguna manera el uso de la CPU, ya que como mencioné anteriormente, varios de ellos se ejecutarán a la vez. No quiero un bucle infinito para acaparar todos los recursos.

EDIT 3: una forma fácil de aproximar el tamaño del objeto es con las clases de Instrumentation de Java; específicamente, el método getObjectSize. Tenga en cuenta que se necesita alguna configuración especial para usar esta herramienta.


Cuidado de los foros de Java . Básicamente cronometrando tu ejecución y luego esperando cuando tomas demasiado tiempo. Como se menciona en el hilo original, ejecutar esto en un hilo separado e interrumpir el hilo de trabajo proporcionará resultados más precisos, al igual que promediar los valores a lo largo del tiempo.

import java.lang.management.*; ThreadMXBean TMB = ManagementFactory.getThreadMXBean(); long time = new Date().getTime() * 1000000; long cput = 0; double cpuperc = -1; while(true){ if( TMB.isThreadCpuTimeSupported() ){ if(new Date().getTime() * 1000000 - time > 1000000000){ //Reset once per second time = new Date().getTime() * 1000000; cput = TMB.getCurrentThreadCpuTime(); } if(!TMB.isThreadCpuTimeEnabled()){ TMB.setThreadCpuTimeEnabled(true); } if(new Date().getTime() * 1000000 - time != 0) cpuperc = (TMB.getCurrentThreadCpuTime() - cput) / (new Date().getTime() * 1000000.0 - time) * 100.0; } //If cpu usage is greater then 50% if(cpuperc > 50.0){ //sleep for a little bit. continue; } //Do cpu intensive stuff }


La única manera en que puede limitar el uso de la CPU de subprocesos es mediante un bloque en un recurso o para llamar a yield () con frecuencia.

Esto no limita el uso de CPU por debajo del 100%, pero le da a otros subprocesos y procesa más timeslices.


Para reducir la CPU, desea dormir sus hilos dentro de los bucles if y while comunes.

while(whatever) { //do something //Note the capitol ''T'' here, this sleeps the current thread. Thread.sleep(someNumberOfMilliSeconds); }

Dormir durante unos cientos de milisegundos reducirá en gran medida el uso de la CPU con poco o ningún resultado notable en el rendimiento.

En cuanto a la memoria, ejecuté un generador de perfiles en los hilos individuales y realicé algunos ajustes de rendimiento. Si estrangulaste la cantidad de memoria disponible para enhebrar, creo que es probable que exista una excepción de falta de memoria o un hilo muerto de hambre. Confío en que la JVM proporcionará tanta memoria como el hilo necesario y trabajará para reducir el uso de memoria al mantener solo objetos esenciales en el alcance en un momento dado.


Puede asignar diferentes prioridades a los hilos para que el hilo más relevante se programe más a menudo.

Mire esta answer para ver si eso ayuda.

Cuando todos los hilos en ejecución tienen la misma prioridad, pueden ejecutarse así:

t1, t2, t3, t1, t2, t3, t1, t2, t3

Cuando le asigna una prioridad diferente a uno de ellos, puede verse así:

t1, t1, t1, t1, t2, t1, t1, t1 t3.

Es decir, el primer hilo se ejecuta "con más frecuencia" que el resto.


Puede obtener mucha información sobre el uso de CPU y memoria a través de JMX , pero no creo que permita ninguna manipulación activa.

Para controlar el uso de CPU hasta cierto punto, puede usar Thread.setPriority() .

En cuanto a la memoria, no existe la memoria por subproceso. El concepto mismo de los hilos de Java significa memoria compartida. La única forma de controlar el uso de la memoria es a través de las opciones de línea de comando como -Xmx, pero no hay forma de manipular la configuración en el tiempo de ejecución.


Si ejecuta los subprocesos en un proceso separado, puede limitar el uso de memoria y limitar el número de CPU o cambiar la prioridad de estos subprocesos.

Sin embargo, cualquier cosa que haga es probable que agregue sobrecarga y complejidad, que a menudo es contraproducente.

A menos que pueda explicar por qué querría hacer esto (p. Ej., Tiene una biblioteca mal escrita en la que no confía y no puede obtener soporte), le sugiero que no la necesite.

La razón por la que no es fácil restringir el uso de la memoria es que solo hay un montón que se comparte. Por lo tanto, un objeto que se utiliza en un hilo se puede usar en otro y no se asigna a un hilo u otro.

Limitar el uso de la CPU significa detener todos los hilos para que no hagan nada, sin embargo, un mejor enfoque es asegurarse de que el hilo no desperdicie la CPU y solo esté activo haciendo el trabajo que debe hacerse, en cuyo caso no lo haría quiero detenerlos haciéndolo.


Si entiendo su problema, una manera sería dormir los subprocesos de forma adaptativa, de forma similar a como se realiza la reproducción de video en Java. Si sabes que quieres un 50% de utilización del núcleo, tu algoritmo debería dormir aproximadamente 0,5 segundos, potencialmente distribuido en un segundo (por ejemplo, cálculo de 0,25 segundos, sueño de 0,25 segundos, etc.). Aquí hay un example de mi reproductor de video.

long starttime = 0; // variable declared //... // for the first time, remember the timestamp if (frameCount == 0) { starttime = System.currentTimeMillis(); } // the next timestamp we want to wake up starttime += (1000.0 / fps); // Wait until the desired next time arrives using nanosecond // accuracy timer (wait(time) isn''t accurate enough on most platforms) LockSupport.parkNanos((long)(Math.max(0, starttime - System.currentTimeMillis()) * 1000000));

Este código dormirá en función de los fotogramas / segundo valor.

Para limitar el uso de la memoria, puede envolver la creación de objetos en un método de fábrica y usar algún tipo de semáforo con permisos limitados en bytes para limitar el tamaño total estimado del objeto (es necesario estimar el tamaño de varios objetos para racionar el semáforo )

package concur; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; public class MemoryLimited { private static Semaphore semaphore = new Semaphore(1024 * 1024, true); // acquire method to get a size length array public static byte[] createArray(int size) throws InterruptedException { // ask the semaphore for the amount of memory semaphore.acquire(size); // if we get here we got the requested memory reserved return new byte[size]; } public static void releaseArray(byte[] array) { // we don''t need the memory of array, release semaphore.release(array.length); } // allocation size, if N > 1M then there will be mutual exclusion static final int N = 600000; // the test program public static void main(String[] args) { // create 2 threaded executor for the demonstration ExecutorService exec = Executors.newFixedThreadPool(2); // what we want to run for allocation testion Runnable run = new Runnable() { @Override public void run() { Random rnd = new Random(); // do it 10 times to be sure we get the desired effect for (int i = 0; i < 10; i++) { try { // sleep randomly to achieve thread interleaving TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10); // ask for N bytes of memory byte[] array = createArray(N); // print current memory occupation log System.out.printf("%s %d: %s (%d)%n", Thread.currentThread().getName(), System.currentTimeMillis(), array, semaphore.availablePermits()); // wait some more for the next thread interleaving TimeUnit.MILLISECONDS.sleep(rnd.nextInt(100) * 10); // release memory, no longer needed releaseArray(array); } catch (InterruptedException e) { e.printStackTrace(); } } } }; // run first task exec.submit(run); // run second task exec.submit(run); // let the executor exit when it has finished processing the runnables exec.shutdown(); } }


Thread.setPriority () puede ayudar, pero no le permite limitar la CPU utilizada por un hilo. De hecho, no he oído hablar de ninguna biblioteca Java que haga esto.

Podría ser posible implementar dicha instalación siempre que sus hilos estén preparados para cooperar. La clave es hacer que los hilos se llamen periódicamente a un programador personalizado y hacer que el programador controle el uso de la CPU con JMX. Pero el problema es que si un hilo no hace que el programador llame con la suficiente frecuencia, puede exceder los límites de aceleración. Y no hay nada que puedas hacer sobre un hilo que se atasca en un ciclo.

Otra ruta teórica para implementar sería usar aislamientos. Desafortunadamente, será difícil encontrar una JVM de propósito general que implemente aislamientos. Además, las API estándar solo te permiten controlar el aislamiento, no los hilos dentro del aislado.