Related But Unsynchronized Threads
Home ] Up ] Unrelated Threads ] [ Related But Unsynchronized Threads ]

 

 

Often a problem can be partitioned into smaller, independent, pieces, and worked on simultaneously using a set of related threads. Some examples of this kind of thread might be:

  • Breaking up a computational problem into smaller, concurrently executing, units
  • A set of "worker threads", perhaps dynamically started on demand, to perform overlapping work. For example:
    • Spawning a new thread to peform work on a new socket connection on a server (see Networking, later in the course)
    • Keeping around a set of threads available to do work, and assigning the work to an available thread on demand.

Here's an example of partitioning a problem -- the problem of determining the factors of a specified number. We'll start up a separate thread to test for factors within a particular range of numbers, and use as many threads as we need to obtain all the factors.

package threads;

public class FindFactors
{
  public static void main(String[] args)
  {
    long number = Long.parseLong(args[0]);
    TestRange.setNumber(number);
    
    System.err.println("Finding the factors of " + number);
    
    // Determine the number of threads to start up,
    // one for each RANGE of divisors to test for.
    int threadCount = (int)(number/RANGE) + 1;
    
    long from = 0, to = RANGE - 1;
    for (int thread = 0; thread < threadCount; thread++)
    {
      new TestRange(from, to).start();
      from += RANGE;
      to += RANGE;
    }
  }
  
  private static final int RANGE = 100;
}

class TestRange extends Thread
{
  public TestRange(long from, long to)
  {
    if (from == 0)
      m_from = 2;
    else
      m_from = from;
    m_to = to;
    
    // Set the thread name to something self-describing
    setName("Factor (" + m_from + " - " + m_to + ")");
  }
  
  public void run()
  {
    System.err.println("Starting thread '" + this.getName() + "'");
    int count = 0;
    for (long div = m_from; div <= m_to && div < m_number; div++)
    {
      if (m_number % div == 0)  // Exactly divisible?
      {
        System.err.println("Factor " + div +
            " found by thread '" + getName() + "'");
        count++;
      }
      yield();
    }
    System.err.println("Thread '" + this.getName() +
        "' ending (found " + count + " factors)");
  }
  
  public static void setNumber(long number)
  {
    m_number = number;
  }
  
  ///// Private data ///////
  
  private static long m_number;   // All TestRange threads share this
  private long m_from, m_to;
}

When supplied with an input parameter of 456, a typical run of this program will output something like:

Finding the factors of 456
Starting thread 'Factor (2 - 99)'
Factor 2 found by thread 'Factor (2 - 99)'
Starting thread 'Factor (100 - 199)'
Starting thread 'Factor (200 - 299)'
Factor 3 found by thread 'Factor (2 - 99)'
Starting thread 'Factor (300 - 399)'
Starting thread 'Factor (400 - 499)'
Factor 4 found by thread 'Factor (2 - 99)'
Factor 6 found by thread 'Factor (2 - 99)'
Factor 8 found by thread 'Factor (2 - 99)'
Factor 12 found by thread 'Factor (2 - 99)'
Factor 114 found by thread 'Factor (100 - 199)'
Factor 19 found by thread 'Factor (2 - 99)'
Factor 228 found by thread 'Factor (200 - 299)'
Thread 'Factor (400 - 499)' ending (found 0 factors)
Thread 'Factor (300 - 399)' ending (found 0 factors)
Factor 24 found by thread 'Factor (2 - 99)'
Factor 152 found by thread 'Factor (100 - 199)'
Thread 'Factor (200 - 299)' ending (found 1 factors)
Factor 38 found by thread 'Factor (2 - 99)'
Thread 'Factor (100 - 199)' ending (found 2 factors)
Factor 57 found by thread 'Factor (2 - 99)'
Factor 76 found by thread 'Factor (2 - 99)'
Thread 'Factor (2 - 99)' ending (found 11 factors)

In the above example, while the threads do share data (the number under test), they only need to read that number. They do not need to change it.  Consequently, there is no synchronization problem.

 
The page was last updated February 19, 2008