views:

83

answers:

3

Hi all, I'm new to the package java.util.concurrent. I've created the following program testing if a number is a prime using a multi and a monothreaded strategy.

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


public class IsPrime
        implements Runnable
    {
    private static final long UPPER_BOUND=100000;
    long value;//the number observed
    private IsPrime(long value)
        {
        this.value=value;
        }
    /** returns wether value is a prime number (simple and stupid method ) */
    private boolean isAPrimeNumber()
        {
        if(value==1 || value==2) return true;
        if(value%2L==0) return false;
        for(long i=3;i< value;++i)
            {
            if(this.value%i==0) return false;
            }
        return true;
        }

    @Override
    /** calls isAPrimeNumber */
    public void run()
        {
        boolean result=isAPrimeNumber();
        //if(result) System.out.println("["+this.value+"]");
        }

    /** loop from 3 to UPPER_BOUND, multithreaded */
    private static long loopMT() 
        {
        long now=System.currentTimeMillis();
        ExecutorService service=Executors.newFixedThreadPool(10); 

        for(long i=3;i< UPPER_BOUND;i+=2)
            {
            service.submit(new IsPrime(i));
            }
        service.shutdown();
        return System.currentTimeMillis()-now;
        }

    /** loop from 3 to UPPER_BOUND, NOT multithreaded */
    private static long loop() 
        {
        long now=System.currentTimeMillis();
        for(long i=3;i< UPPER_BOUND;i+=2)
            {
            new IsPrime(i).run();
            }
        return System.currentTimeMillis()-now;
        }

    public static void main(String[] args)
        {
        long n1=IsPrime.loop();
        long n2=IsPrime.loopMT();
        System.out.println(""+n1+" >>> "+n2);   
        }
    }

for the method loopMT, is it the correct way to use the classes of the package java.util.concurrent ? Is there another, (safer, more elegant) way to write this program ? Can I use System.out in a multithreaded environement ?

Many thanks for your suggestions

Pierre

+1  A: 

As it is currently written loopMT is not waiting for the submitted tasks to complete.

You have a few options:

  • Call awaitTermination() to wait for all primality tests to complete, writing the results to System.out as you are currently doing.
  • Change the interface from Runnable to Callable<Boolean> or maybe Callable<Map.Entry<Long, Boolean>> and use service.invokeAll() (then you will get all results returned at once.)
  • Store the results in a synchronized Map and read it when all the primality tests have completed
  • Have the run method send the results to a BlockingQueue or SynchronousQueue and have the loopMT method loop fetching the results from the queue and printing them. This is the option I would prefer.
  • Use a queue indirectly, via a CompletionService.
finnw
`SynchronousQueue` is more like channel in fact, I doubt that it is appropriate here. And why use synchronized map but not `ConcurrentMap`? Its throughput is much better in most cases.
Rorick
Yes a `SynchronousQueue` is a channel and that is what you want, if you have another thread blocked reading it, which is what I am suggesting. `ConcurrentMap` is fine (though you don't need its extra methods.)
finnw
+1  A: 

Since this calculation is likely CPU bound, there is no advantage to running more threads than you have CPU cores. Extra threads after that only add to overhead.

amarillion
+2  A: 

As System.out is an instance of PrintStream it is thread-safe. So it is fine for training examples. But generally output from different threads doesn't seem like a good idea to me. It's better to have dedicated output thread that accepts requests for output asynchronously.

Probably, I'd rather implemented Callable<Boolean> as finnw suggested, otherwise I see no reason in IsPrime class except of CPU consumption.

Rorick