Home > front end >  Is there a way to limit number of Threads running at the same time
Is there a way to limit number of Threads running at the same time

Time:12-11

I have a list of objects List<EventuelleDestination> ev and I need to create a thread that will serialize the data for each element of the list. However, only 3 threads are allowed to run at the same time. I have done a fair share of research on ThreadPools and other classes, but I still have no idea how to implement these this limit in my method.

If it can be of any help, here is the task each thread must accomplish until the List is iterated through.

    public void serializeDestinationEmploye(EventuelleDestination e) {
    Gson gson = new Gson();
    String filename = "/"   employeDao.getEmploye().getId()   "_"   entrepriseDao.retrouveEmplacementIdParDepartementId(e.getEventuelAcceuillant().getId())   "_"   e.getEventuelAcceuillant().getId()   ".json";

    try {
        Writer writer = new FileWriter(dossierSoumissions.toString()   filename);

        new Gson().toJson(e, writer);
        writer.close();

        System.out.println(e   " has been serialized...");
    } catch (IOException fileNotFoundException) {
        fileNotFoundException.printStackTrace();
    }
}

CodePudding user response:

Executors framework

Java 5 brought the Executors framework to greatly simplify threaded work. See the links in Answer by Chaudhuri.

Runnable

Define your task as a Runnable or Callable.

package work.basil.example.threading;

import java.time.Instant;
import java.util.concurrent.ThreadLocalRandom;

public class Reporter implements Runnable
{
    private Integer reportId;

    public Reporter ( final Integer reportId )
    {
        this.reportId = reportId;
    }

    @Override
    public void run ( )
    {
        // Simulate doing hard work by sleeping this thread a random number of milliseconds.
        try { Thread.sleep( ThreadLocalRandom.current().nextInt( 5 , 100 ) ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
        String message = Thread.currentThread().getName()   " reporting id: "   this.reportId   " at "   Instant.now();
        System.out.println( message );
    }
}

ExecutorService

Instantiate a bunch of those tasks. Instantiate an executor service, backed by your specified three threads. Wait for tasks to complete, and shutdown the executor service.

package work.basil.example.threading;

import java.time.Instant;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class App
{
    public static void main ( String[] args )
    {
        App app = new App();
        app.demo();
    }

    private void demo ( )
    {
        List < Reporter > tasks =
                IntStream
                        .range( 100 , 200 )           // Generate a range of numbers from 100 through 199. 
                        .mapToObj( Reporter :: new )  // Method reference for the constructor of our `Reporter` class.
                        .toList();                    // Collect all the newly instantiated `Reporter` objects into a `List`. 
        ExecutorService executorService = Executors.newFixedThreadPool( 3 ); // Hard-code to three, per the Stack Overflow Question's requirements.
        tasks.stream().forEach( executorService :: submit );  // Submit to our executor service each of the collected tasks in our list.
        this.shutdownAndAwaitTermination( executorService );
    }

    // Slightly modified version of boilerplate taken from Javadoc:
    // https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ExecutorService.html
    void shutdownAndAwaitTermination ( ExecutorService executorService )
    {
        executorService.shutdown(); // Disable new tasks from being submitted
        try
        {
            // Wait a while for existing tasks to terminate
            if ( ! executorService.awaitTermination( 120 , TimeUnit.SECONDS ) )
            {
                executorService.shutdownNow(); // Cancel currently executing tasks
                // Wait a while for tasks to respond to being cancelled
                if ( ! executorService.awaitTermination( 120 , TimeUnit.SECONDS ) )
                { System.err.println( "Executor service did not terminate. "   Instant.now() ); }
            }
        }
        catch ( InterruptedException ex )
        {
            // (Re-)Cancel if current thread also interrupted
            executorService.shutdownNow();
            // Preserve interrupt status
            Thread.currentThread().interrupt();
        }
    }
}

When run:

pool-1-thread-2 reporting id: 101 at 2022-12-11T01:20:49.336052Z
pool-1-thread-1 reporting id: 100 at 2022-12-11T01:20:49.342575Z
pool-1-thread-3 reporting id: 102 at 2022-12-11T01:20:49.350614Z
pool-1-thread-2 reporting id: 103 at 2022-12-11T01:20:49.371866Z
pool-1-thread-1 reporting id: 104 at 2022-12-11T01:20:49.392103Z
pool-1-thread-2 reporting id: 106 at 2022-12-11T01:20:49.430291Z
pool-1-thread-3 reporting id: 105 at 2022-12-11T01:20:49.437875Z
pool-1-thread-3 reporting id: 109 at 2022-12-11T01:20:49.450208Z
pool-1-thread-3 reporting id: 110 at 2022-12-11T01:20:49.478506Z
pool-1-thread-1 reporting id: 107 at 2022-12-11T01:20:49.488794Z
pool-1-thread-1 reporting id: 112 at 2022-12-11T01:20:49.501638Z
pool-1-thread-2 reporting id: 108 at 2022-12-11T01:20:49.512510Z
pool-1-thread-3 reporting id: 111 at 2022-12-11T01:20:49.516905Z
pool-1-thread-1 reporting id: 113 at 2022-12-11T01:20:49.602825Z
pool-1-thread-2 reporting id: 114 at 2022-12-11T01:20:49.614678Z
pool-1-thread-3 reporting id: 115 at 2022-12-11T01:20:49.621172Z
pool-1-thread-1 reporting id: 116 at 2022-12-11T01:20:49.659485Z
pool-1-thread-2 reporting id: 117 at 2022-12-11T01:20:49.668028Z
pool-1-thread-3 reporting id: 118 at 2022-12-11T01:20:49.715350Z
pool-1-thread-2 reporting id: 120 at 2022-12-11T01:20:49.740292Z
pool-1-thread-1 reporting id: 119 at 2022-12-11T01:20:49.740722Z
pool-1-thread-2 reporting id: 122 at 2022-12-11T01:20:49.765576Z
pool-1-thread-3 reporting id: 121 at 2022-12-11T01:20:49.779553Z
pool-1-thread-2 reporting id: 124 at 2022-12-11T01:20:49.801574Z
pool-1-thread-1 reporting id: 123 at 2022-12-11T01:20:49.833277Z
pool-1-thread-3 reporting id: 125 at 2022-12-11T01:20:49.838785Z
pool-1-thread-2 reporting id: 126 at 2022-12-11T01:20:49.861583Z
pool-1-thread-1 reporting id: 127 at 2022-12-11T01:20:49.884080Z
pool-1-thread-2 reporting id: 129 at 2022-12-11T01:20:49.895801Z
pool-1-thread-3 reporting id: 128 at 2022-12-11T01:20:49.922937Z
pool-1-thread-1 reporting id: 130 at 2022-12-11T01:20:49.922936Z
pool-1-thread-2 reporting id: 131 at 2022-12-11T01:20:49.927722Z
pool-1-thread-1 reporting id: 133 at 2022-12-11T01:20:49.978305Z
pool-1-thread-3 reporting id: 132 at 2022-12-11T01:20:50.000371Z
pool-1-thread-2 reporting id: 134 at 2022-12-11T01:20:50.025637Z
pool-1-thread-1 reporting id: 135 at 2022-12-11T01:20:50.025969Z
pool-1-thread-1 reporting id: 138 at 2022-12-11T01:20:50.078081Z
pool-1-thread-3 reporting id: 136 at 2022-12-11T01:20:50.089295Z
pool-1-thread-2 reporting id: 137 at 2022-12-11T01:20:50.116680Z
pool-1-thread-3 reporting id: 140 at 2022-12-11T01:20:50.142114Z
pool-1-thread-2 reporting id: 141 at 2022-12-11T01:20:50.144543Z
pool-1-thread-2 reporting id: 143 at 2022-12-11T01:20:50.173864Z
pool-1-thread-1 reporting id: 139 at 2022-12-11T01:20:50.177693Z
pool-1-thread-1 reporting id: 145 at 2022-12-11T01:20:50.193305Z
pool-1-thread-3 reporting id: 142 at 2022-12-11T01:20:50.213100Z
pool-1-thread-2 reporting id: 144 at 2022-12-11T01:20:50.258059Z
pool-1-thread-1 reporting id: 146 at 2022-12-11T01:20:50.281883Z
pool-1-thread-3 reporting id: 147 at 2022-12-11T01:20:50.295357Z
pool-1-thread-2 reporting id: 148 at 2022-12-11T01:20:50.297879Z
pool-1-thread-3 reporting id: 150 at 2022-12-11T01:20:50.310537Z
pool-1-thread-2 reporting id: 151 at 2022-12-11T01:20:50.334702Z
pool-1-thread-1 reporting id: 149 at 2022-12-11T01:20:50.366817Z
pool-1-thread-2 reporting id: 153 at 2022-12-11T01:20:50.388458Z
pool-1-thread-1 reporting id: 154 at 2022-12-11T01:20:50.410089Z
pool-1-thread-3 reporting id: 152 at 2022-12-11T01:20:50.410866Z
pool-1-thread-2 reporting id: 155 at 2022-12-11T01:20:50.438706Z
pool-1-thread-2 reporting id: 158 at 2022-12-11T01:20:50.457866Z
pool-1-thread-3 reporting id: 157 at 2022-12-11T01:20:50.483979Z
pool-1-thread-1 reporting id: 156 at 2022-12-11T01:20:50.509379Z
pool-1-thread-2 reporting id: 159 at 2022-12-11T01:20:50.528403Z
pool-1-thread-1 reporting id: 161 at 2022-12-11T01:20:50.528355Z
pool-1-thread-3 reporting id: 160 at 2022-12-11T01:20:50.540466Z
pool-1-thread-3 reporting id: 164 at 2022-12-11T01:20:50.553258Z
pool-1-thread-3 reporting id: 165 at 2022-12-11T01:20:50.563534Z
pool-1-thread-1 reporting id: 163 at 2022-12-11T01:20:50.573721Z
pool-1-thread-3 reporting id: 166 at 2022-12-11T01:20:50.611714Z
pool-1-thread-2 reporting id: 162 at 2022-12-11T01:20:50.630698Z
pool-1-thread-1 reporting id: 167 at 2022-12-11T01:20:50.647767Z
pool-1-thread-3 reporting id: 168 at 2022-12-11T01:20:50.704881Z
pool-1-thread-2 reporting id: 169 at 2022-12-11T01:20:50.706819Z
pool-1-thread-1 reporting id: 170 at 2022-12-11T01:20:50.738498Z
pool-1-thread-2 reporting id: 172 at 2022-12-11T01:20:50.761919Z
pool-1-thread-1 reporting id: 173 at 2022-12-11T01:20:50.789843Z
pool-1-thread-2 reporting id: 174 at 2022-12-11T01:20:50.800720Z
pool-1-thread-3 reporting id: 171 at 2022-12-11T01:20:50.800720Z
pool-1-thread-3 reporting id: 177 at 2022-12-11T01:20:50.812244Z
pool-1-thread-1 reporting id: 175 at 2022-12-11T01:20:50.819188Z
pool-1-thread-2 reporting id: 176 at 2022-12-11T01:20:50.856135Z
pool-1-thread-1 reporting id: 179 at 2022-12-11T01:20:50.865442Z
pool-1-thread-1 reporting id: 181 at 2022-12-11T01:20:50.875508Z
pool-1-thread-3 reporting id: 178 at 2022-12-11T01:20:50.908384Z
pool-1-thread-2 reporting id: 180 at 2022-12-11T01:20:50.911297Z
pool-1-thread-3 reporting id: 183 at 2022-12-11T01:20:50.922288Z
pool-1-thread-2 reporting id: 184 at 2022-12-11T01:20:50.934034Z
pool-1-thread-1 reporting id: 182 at 2022-12-11T01:20:50.947619Z
pool-1-thread-3 reporting id: 185 at 2022-12-11T01:20:50.955411Z
pool-1-thread-1 reporting id: 187 at 2022-12-11T01:20:50.973815Z
pool-1-thread-3 reporting id: 188 at 2022-12-11T01:20:50.980241Z
pool-1-thread-1 reporting id: 189 at 2022-12-11T01:20:50.989099Z
pool-1-thread-2 reporting id: 186 at 2022-12-11T01:20:51.037188Z
pool-1-thread-3 reporting id: 190 at 2022-12-11T01:20:51.067505Z
pool-1-thread-2 reporting id: 192 at 2022-12-11T01:20:51.083379Z
pool-1-thread-1 reporting id: 191 at 2022-12-11T01:20:51.092831Z
pool-1-thread-1 reporting id: 195 at 2022-12-11T01:20:51.099644Z
pool-1-thread-2 reporting id: 194 at 2022-12-11T01:20:51.110563Z
pool-1-thread-3 reporting id: 193 at 2022-12-11T01:20:51.110563Z
pool-1-thread-2 reporting id: 197 at 2022-12-11T01:20:51.153739Z
pool-1-thread-3 reporting id: 198 at 2022-12-11T01:20:51.194933Z
pool-1-thread-1 reporting id: 196 at 2022-12-11T01:20:51.201879Z
pool-1-thread-2 reporting id: 199 at 2022-12-11T01:20:51.205119Z

Be aware that output to System.out does not necessarily appear on the console chronologically. If you care, always include a timestamp such as Instant.now.

All this has been covered before on Stack Overflow. Search to learn more.

CodePudding user response:

Spawn three threads and let them do the work, taking tasks from a queue. There will be no more threads than the number that you spawn to work on the tasks.

But a simpler way to do this is to use the Java standard class ThreadPoolExecutor that takes care of the thread spawning and pool management for you.

There is also a nice tutorial on executors at https://docs.oracle.com/javase/tutorial/essential/concurrency/executors.html

CodePudding user response:

Is there a way to limit number of Threads running at the same time.

Not directly, no. There are no thread scheduler hooks for doing this kind of thing.

Your realistic options are to create a pool of 3 threads:

  • by hand,
  • using an ExecutorService with a bounded thread pool, or
  • using a 3rd-party thread pool library.

Then you arrange to have the tasks handed out to the threads in the pool via a queue.

FWIW: the ExecutorService approach is the simplest because it taks care of both the thread pool management and the task queuing. See the other answers for details.


If you didn't have a hard requirement of 3 threads, another potential option would be to use a Stream with a parallel step. This would use the JVM's common fork-join pool1 to do the tasks in parallel. The problem is that you don't get to directly control that pool's size, and other tasks may be queued for that pool. Also, doing potentially blocking I/O in a fork-join pool can be problematic for parts of your application that are using the common pool; see the ForkJoinPool javadoc.

In theory, you could create a thread for each task and write the tasks to use (say) a shared Semaphore to limit the number of threads that are running the tasks at any given time. But creating threads is expensive, and they use a substantial amount of memory (even when they are blocked) so this is not a practical solution.


1 - This is how the current implementation does it. AFAIK, this is not stated in the javadoc ...

  • Related