简体   繁体   中英

Adding Thread in ThreadPool in Executor Service

I am working on a Multithreading Program in which I am trying to make sure each Thread is running for 30 minutes . Suppose if we have 10 threads then each thread out of 10 should run for 30 minutes .

Below is my code-

class ThreadTask implements Runnable {
    private final long endTime;

    public ThreadTask(long endTime) {
        this.endTime = endTime;
    }

    @Override
    public void run() {

        while (System.currentTimeMillis() <= endTime) {

            // do something meaningful

        }   
    }
}

public class TestPool {

    public static void main(String[] args) {

        // create thread pool with given size
        ExecutorService service = Executors.newFixedThreadPool(1000); 

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (30 * 60 * 1000);

        for (int i = 0; i < threads; i++) {
            service.submit(new ThreadTask(endTime));
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
    }
}

Now my question is-

Does the above code guarantee that each thread is starting at the same time and running for 30 minutes ? I am not sure how much time it takes to put the thread in Thread Pool . But it looks like it might be possible that some of the thread will start little bit late and they won't be running for exactly 30 minutes , might be less than 30 minutes.

I am looking for each thread should start at same time and they should run for exactly 30 minutes

Short answer : No, all the threads will not start exactly at the same time (depending on what your tolerance is, it could be 'quite' negligible). And depending on what something meaningful does, there is very little chance that each thread runs exactly 30 minutes (again here, your time granularity could make this assertion wrong).

Leads :

  • To make sure to maximize your chances that all threads start as close as possible from each other, create your threads first and then submit it to the executor. Thread creation, in Java as in other languages, is an expensive operation.
  • For the threads to run exactly 30 minutes, I would recommend that each thread computes itself its termination time since the argument your are currently passing to the constructor could already affect your precision (due to the thread creation time).
  • It is usually not recommended (except if your run java on a monster machine or a calculus grid) to create a thread pool with 1000 threads. Keep in mind that if the physical machine does not have as many cores as threads, a context switch will occur each time the JVM decides which thread should run.

EDIT :

public class TestPool {

    public static void main(String[] args) {

        // create thread pool with given size
        ExecutorService service = Executors.newFixedThreadPool(10); 

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (30 * 60 * 1000);

        ThreadTask[] threadTasks = new ThreadTask[threads];
        for (int i = 0; i < threads; i++) {
            threadTasks[i] = new ThreadTask(endTime);
        }

        for (ThreadTask tt : threadTasks) {
            service.submit(tt);
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
    }
}

At first glance, this looks like a somewhat unrealistic multithreading excercise project. But you say I am working on a Multithreading Program which suggests there is a real-world application background to it.

If that's the case: Do not create 1000 threads just because you can. Instead, say what you actually want to achieve.

About your requirements: To start all the threads almost at the same time with minimum delay, you can prestartAllCoreThreads of a ThreadPoolExecutor . Submit Runnables that have // do something meaningful in their run Method. To limit the run time to 30 minutes, schedule a TimerTask that after 30min shuts down the ThreadPoolExecutor with shutdownNow. When creating the ThreadPoolExecutor, you can use a fixed-size BlockingQueue with a size in the order of your desired thread count to avoid submitting too many jobs.

Consider using countdown latch to achieve maximum parallelism. Basically you can create singleton/static countdownLatch with total count 1 and let multiple threads waited up for same countdown. check below what I've done

The main thread that dictates the thread starting time.

package mylab.threads;

import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainThread extends TimerTask {

    private static CountDownLatch countDown = new CountDownLatch(1);

    private ExecutorService es = Executors.newCachedThreadPool();

    @Override
    public void run() {

    try {


        Thread1 thread1 = new Thread1();
        thread1.setDoneSignal(countDown);
        es.submit(thread1);

        Thread2 thread2 = new Thread2();
        thread2.setDoneSignal(countDown);
        es.submit(thread2);

        System.out.println("waiting main.. ");
        synchronized(this) {
        this.wait(2000);
        }
        System.out.println("kick off threads..");
        countDown.countDown();

    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    }

}

Define threads you want to run parallel

package mylab.threads;

import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;

public class Thread1 extends TimerTask{

    private CountDownLatch doneSignal = null;

    /**
     * @return the doneSignal
     */
    public CountDownLatch getDoneSignal() {
        return doneSignal;
    }

    /**
     * @param doneSignal the doneSignal to set
     */
    public void setDoneSignal(CountDownLatch doneSignal) {
        this.doneSignal = doneSignal;
    }

    @Override
    public void run() {

    try {
        this.doneSignal.await();
        System.out.println("get going thread 1 -"+new Date().getTime());
        synchronized(this) {
        this.wait(3000);
        }
        System.out.println("Exiting thread 1 - "+new Date().getTime());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }

}


package mylab.threads;

import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;

public class Thread2 extends TimerTask{

    private CountDownLatch doneSignal = null;

    /**
     * @return the doneSignal
     */
    public CountDownLatch getDoneSignal() {
        return doneSignal;
    }

    /**
     * @param doneSignal the doneSignal to set
     */
    public void setDoneSignal(CountDownLatch doneSignal) {
        this.doneSignal = doneSignal;
    }

    @Override
    public void run() {

    try {
        this.doneSignal.await();
        System.out.println("get going thread 2 -"+new Date().getTime());
        synchronized(this) {
        this.wait(3000);
        }
        System.out.println("Exiting thread 2 - "+new Date().getTime());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }
}

Finally run main thread.

package mylab.threads;

public class ThreadTest {

    /**
     * @param args
     */
    public static void main(String[] args) {

    MainThread mt = new MainThread();
    mt.run();

    }

}

Here is the output

waiting main.. 
kick off threads..
get going thread 1 -1387513662107
get going thread 2 -1387513662107
Exiting thread 1 - 1387513665108
Exiting thread 2 - 1387513665108

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