简体   繁体   中英

How to run X tasks on Y threads in Java?

I want to meassure an average time of executing a task on 5 threads doing 100 tasks.

For time meassuring purposes I use nanoTime()

The task is calling one specific method, let's call it foo(); I don't create any additional classes.

In my code I create a task:

Runnable thExecute = new Runnable(){
  @Override
  public void run(){
    foo();
  }
};

And then I create a thread:

Thread th = new Thread(thExecute);
long start = System.nanoTime();
th.run();
long stop = System.nanoTime();

This would be great if I had the same number of tasks as threads. I tried to create arrays of threads and tasks:

Runnable[] thExecutes = new Runnable[100];
Thread[] ths = new Thread[5];

But now I don't know what to do next. I know they should be queued somehow and probably I should use Executor class. I use Java 6.

Edit: At first I didn't mean what I wrote. Now I know I want average time + highest time.

First thing to note: you should not expect precise results, if you measure performance by yourself. There are tools that do it for you, providing much more reliable results.

If you want to do it by yourself, use ExecutorService:

ExecutorService service = Executors.newFixedThreadPool(5);
long startTs = System.nanoTime();

List<Future> futures = new ArrayList<>();
for (Runnable r : runnables) {
    futures.add(service.submit(r));
}
for (Future f : futures) { 
    f.get(); 
}

long durationNs = System.nanoTime() - startTs;

And again: since you are measuring nanoseconds, I strongly encourage you to avoid manual measurements, because there are many factors that will spoil the results: no warmup, setup expenses, etc.

Update : to measure execution time of every task, you can submit Callable<Long> instead of Runnable

public long call() {
    long startTs = System.nanoTime();
    // do the task
    return System.nanoTime() - startTs;
}

Now Future will return the execution time, you can print it or gather in a list:

for (Future<Long> f : futures) {
    long spentTime = f.get();
}

You can use an Executor :

ExecutorService executorService = Executors.newFixedThreadPool(5);
long start = System.nanoTime();
for (int i = 0; i < 100; i++) {
    executorService.submit(new Runnable() {

        @Override
        public void run() {
            foo();
        }
    });
}
try {
    // set whatever timeout value you want (must be > than the execution time)
    executorService.awaitTermination(1, TimeUnit.MINUTES); 
} catch (InterruptedException e) {
    e.printStackTrace();
}
long stop = System.nanoTime();

It will create an executor with a fix size of 5 threads then push 100 task to teh executor. The executor will dispatch the task on each thread.

I always like to use ThreadPoolExecutor

ThreadPoolExecutor would be more effective if you have customized many or all of below parameters preferably : BlockingQueu e Size (control unbounded queue size) , ThreadFactory for custom thread life cycle management & RejectedExecutionHandler to handle rejected tasks .

ThreadPoolExecutor(int corePoolSize, 
               int maximumPoolSize, 
               long keepAliveTime, 
               TimeUnit unit, 
               BlockingQueue<Runnable> workQueue, 
               ThreadFactory threadFactory,
               RejectedExecutionHandler handler)

Sample code:

import java.util.concurrent.*;

import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy;

class SimpleThreadFactory implements ThreadFactory {
   String name;
   static int threadNo = 0;

   public SimpleThreadFactory (String name){
       this.name = name;
   }
   public Thread newThread(Runnable r) {
     ++threadNo;
     System.out.println("thread no:"+threadNo);
     return new Thread(r,name+":"+threadNo );
   }
   public static void main(String args[]){
        SimpleThreadFactory factory = new SimpleThreadFactory("Factory Thread");
        final ThreadPoolExecutor executor = new ThreadPoolExecutor(5,20,10,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(10),factory,new ThreadPoolExecutor.DiscardPolicy());
        for ( int i=0; i < 1000; i++){
            executor.submit(new Runnable(){
                 public void run(){
                   // Add t1 here
                    System.out.println("Thread Name in Runnable:"+Thread.currentThread().getName()+ " of "+ executor.getPoolSize() );
                   // print System.currentTimeMillies - t1 here
                 }
            });
        }
        executor.shutdown();
    }
 }

Your code simply does not run in a separate thread because of this

th.run();

you should call start() instead of run() to achieve multi-thread functionality

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM