0

I'm new at Java. I was just experimenting with threads, and I wanted to create something like a Thread Pool (if this is actually what I am doing..).

Basically I have a while loop which fires Threads until there are still tasks to be executed && while max concurrent threads is not greater than n. Each thread use java.util.concurrent.locks.ReentrantLock to provide a lock around the the task count variable which is decreased in each thread and the thread count variable which is increased as soon the thread starts and decreased just before the thread ends(code smell?):

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test { 
   public static void main(String[] args) {

      //overcome limitation of closure not being able to modify outer variable with arr.
      final int[] runningThreads = {0};
      final int[] taskcount = {10};

      final Lock _mutex = new ReentrantLock(true);

      int maxThreadQty = 3;


      while ((taskcount[0] > 0) && (runningThreads[0] < maxThreadQty))  {

         new Thread("T") {
             public void run() {
                  System.out.println("New Thread Started");
                  _mutex.lock();
                  runningThreads[0]++;
                  System.out.println("Running Threads: " + runningThreads[0]);
                  System.out.println("Times to go: " + taskcount[0]);
                  _mutex.unlock();
                  // actually do something;
                  _mutex.lock();
                  taskcount[0]--;
                  runningThreads[0]--;
                  _mutex.unlock();
             }

          }.start();
      }
   }
}

When I run the code, new Threads keep being fired forever and task count is only decreased like two or three times......

Last lines of output (read times to go as tasks to go):

Running Threads: 565
Times to go: 8
Running Threads: 566
Times to go: 8
Running Threads: 567
Times to go: 8
Running Threads: 568
Times to go: 8
Running Threads: 569
Times to go: 8
Running Threads: 570
Times to go: 8
Running Threads: 571
Times to go: 8
Running Threads: 572
Times to go: 8
Running Threads: 573
Times to go: 8
Running Threads: 574
Times to go: 8
Running Threads: 575
Times to go: 8

CTRL-C

I am sure there must be something totally wrong with the way I am using Threads or locks.. but as a java newbie there's so many things that I could be missing out (probably even most basic ones) that some help and some putting me back on the right path would be very appreciated...! Thank you.

I used this as a reference for threads: http://tutorials.jenkov.com/java-concurrency/creating-and-starting-threads.html

And then this stackoverflow answer to see how to use ReentrantLock: https://stackoverflow.com/a/12510490/988591

This for the closure not being able to modify outer variables workaround (using arrays values): http://c2.com/cgi/wiki?ClosuresThatWorkAroundFinalLimitation

Community
  • 1
  • 1
Redoman
  • 3,059
  • 3
  • 34
  • 62
  • 1
    You are creating "subthreads" in a main thread. Nobody can tell which thread will be allowed by the processor to execute. That means technically your main thread may create a random number of new threads before any of these subthreads have the chance to reduce the counter. – Moh-Aw Apr 25 '14 at 12:56
  • Thanks, if you care doing so, would you like to explain in a row or two the big outlines of how a correct implementation would work? Thanks! – Redoman Apr 25 '14 at 13:27

1 Answers1

1

Couldn't you use the built in thread pool functionality?

If not, the problem is that runningThreads doesn't get increased until each thread starts and has acquired the lock. In practice the main thread may run for quite some time, all the while spinning up new threads without limit.

One solution might be to increase the runningThreads variable on the main thread, just before starting the new thread, but leave decreasing the variable inside each of the worker threads.

I don't want to suggest that everything else about your code is "good" (creating a robust thread-pool implementation can be quite a difficult and involved task) but a minimal change that may avoid the problem could be

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Test { 
   public static void main(String[] args) {

      //overcome limitation of closure not being able to modify outer variable with arr.
      final int[] runningThreads = {0};
      final int[] taskcount = {10};

      final Lock _mutex = new ReentrantLock(true);

      int maxThreadQty = 3;


      while ((taskcount[0] > 0) && (runningThreads[0] < maxThreadQty))  {
         System.out.println("New Thread Started");
         _mutex.lock();
         runningThreads[0]++;
         System.out.println("Running Threads: " + runningThreads[0]);
         System.out.println("Times to go: " + taskcount[0]);
         _mutex.unlock();
         new Thread("T") {
             public void run() {
                  // actually do something;
                  _mutex.lock();
                  taskcount[0]--;
                  runningThreads[0]--;
                  _mutex.unlock();
             }

          }.start();
      }
   }
}
Daniel Renshaw
  • 33,729
  • 8
  • 75
  • 94
  • Thanks! This way the code executes for the required number of tasks! But number of threads is always 1: ```New Thread Started Running Threads: 1 Times to go: 5 New Thread Started Running Threads: 1 Times to go: 4 New Thread Started Running Threads: 1 Times to go: 3 New Thread Started Running Threads: 1 Times to go: 2 New Thread Started Running Threads: 1 Times to go: 1 New Thread Started Running Threads: 1 Times to go: 0``` What do you think it makes it behave so? – Redoman Apr 25 '14 at 13:13
  • @jj_ Have you actually put anything in the "actually do something" section? If not, it's quite possible the thread finishes before the next one starts. – Daniel Renshaw Apr 25 '14 at 13:16
  • It probably happens because each thread actually lasts so short that they do never overlap... possible? I added Thread.sleep(10000) and then it looks like they do sum up till the max allowed thread count! I guess you did it! Thanks! – Redoman Apr 25 '14 at 13:20
  • Yea we wrote that at the same time ;) – Redoman Apr 25 '14 at 13:20
  • A big pitfall with the code is now that as soon as the max count for threads in reached by looping with "while", "while" will no longer evaluate to true so it will stop looping... and so other threads for remaining task will never be executed :) – Redoman Apr 25 '14 at 14:10
  • I fixed it by putting the second condition inside an inner while: ```while (taskcount[0] > 0) { while (runningThreads[0] < maxThreadQty) { ... } } ```This way even if the threads reach their maximum count, execution is forced to loop because there are still tasks to do, that only get executed by threads when they have not reached their maximum count. – Redoman Apr 25 '14 at 15:38