[ACCEPTED]-Throttling CPU/Memory usage of a Thread in Java?-throttling

Accepted answer
Score: 32

If I understand your problem, one way would 15 be to adaptively sleep the threads, similarly 14 as video playback is done in Java. If you 13 know you want 50% core utilization, the 12 your algorithm should sleep approximately 11 0.5 seconds - potentially distributed within 10 a second (e.g. 0.25 sec computation, 0.25 9 sec sleep, e.t.c.). Here is an example from my 8 video player.

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));

This code will sleep based 7 on the frames/second value.

To throttle the 6 memory usage, you could wrap your object 5 creation into a factory method, and use 4 some kind of semaphore with a limited permits 3 as bytes to limit the total estimated object 2 size (you need to estimate the size of various 1 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();
    }
}
Score: 6

Care of Java Forums. Basically timing your execution 5 and then waiting when your taking too much 4 time. As is mentioned in the original thread, running 3 this in a separate thread and interrupting 2 the work thread will give more accurate 1 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
}
Score: 5

You can get a lot of info about CPU and 9 memory usage via JMX, but I don't think it 8 allows any active manipulation.

For controlling 7 CPU usage to some degree, you can use Thread.setPriority().

As 6 for memory, there is no such thing as per-thread 5 memory. The very concept of Java threads 4 means shared memory. The only way to control 3 memory usage is via the command line options 2 like -Xmx, but there's no way to manipulate 1 the settings at runtime.

Score: 2

If you run the threads in a separate process 19 you can cap the memory usage and limit the 18 number of CPUs or change the priority of 17 these threads.

However, anything you do is 16 likely to add overhead and complexity which 15 is often counter-productive.

Unless you can 14 explain why you would want to do this (e.g. you 13 have a badly written library you don't trust 12 and can't get support for) I would suggest 11 you don't need to.

The reason its not easy 10 to restrict memory usage is there is only 9 one heap which is shared. So an object which 8 is used in one thread is usable in another 7 and is not assigned to one thread or another.

Limiting 6 CPU usage means stopping all the threads 5 so they don't do anything, however a better 4 approach is to make sure the thread don't 3 waste CPU and are only active doing work 2 which needs to be done, in which case you 1 wouldn't want to stop them doing it.

Score: 1

You can assign different priorities to the 8 threads so the most relevant thread get 7 scheduled more often.

Look at this answer to see 6 if that helps.

When all the running thread 5 have the same priority they may run like 4 this:

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

When you assign a different priority 3 to one of them it may look like:

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

That is, the 2 first thread runs "more often" that 1 the rest.

Score: 1

Why not instead of doing "threading" do 6 cooperative multitasking, would be interesting 5 to see if you can manipulate http://www.janino.net/ to run a program 4 for a certain amount of time/set of intstructions, then 3 stop and run the next program. At least 2 that way its fair, give everyone the same 1 time slice...

Score: 0

Thread.setPriority() may help, but it doesn't 19 allow you to cap the CPU used by a thread. In 18 fact, I've haven't heard of any Java library 17 that does this.

It might be possible to implement 16 such a facility provided that your threads 15 are prepared to cooperate. The key is to 14 have the threads periodically call into 13 a custom scheduler, and have the scheduler 12 monitor thread CPU usage using JMX. But 11 the problem is that if some thread doesn't 10 make the scheduler call often enough it 9 may well exceed the throttling limits. And 8 there's nothing you can do about a thread 7 that gets stuck in a loop.

Another theoretical 6 route to implementing would be to use Isolates. Unfortunately, you 5 will be hard pressed to find a general purpose 4 JVM that implements isolates. Besides, the 3 standard APIs only allow you to control 2 the isolate, not the threads within the 1 isolate.

Score: 0

The only way you can limit Thread CPU usage 4 is by either block on a resource or to call 3 yield() frequently.

This does not limit CPU 2 usage below 100% but gives other threads 1 and processes more timeslices.

More Related questions