Throttling CPU/Memory usage of a Thread in Java?
If I understand your problem, one way would be to adaptively sleep the threads, similarly as video playback is done in Java. If you know you want 50% core utilization, the your algorithm should sleep approximately 0.5 seconds - potentially distributed within a second (e.g. 0.25 sec computation, 0.25 sec sleep, e.t.c.). Here is an example from my video player.
long starttime = 0; // variable declared//...// for the first time, remember the timestampif (frameCount == 0) { starttime = System.currentTimeMillis();}// the next timestamp we want to wake upstarttime += (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));
This code will sleep based on the frames/second value.
To throttle the memory usage, you could wrap your object creation into a factory method, and use some kind of semaphore with a limited permits as bytes to limit the total estimated object size (you need to estimate the size of various objects to ration the semaphore).
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(); }}
Care of Java Forums. Basically timing your execution and then waiting when your taking too much time. As is mentioned in the original thread, running this in a separate thread and interrupting the work thread will give more accurate results, as will averaging values over time.
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}
You can get a lot of info about CPU and memory usage via JMX, but I don't think it allows any active manipulation.
For controlling CPU usage to some degree, you can use Thread.setPriority().
As for memory, there is no such thing as per-thread memory. The very concept of Java threads means shared memory. The only way to control memory usage is via the command line options like -Xmx, but there's no way to manipulate the settings at runtime.