Search code examples
javamultithreadingobjectserializationthreadpool

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


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

Solution

  • 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.