[concurrency-interest] Fixed thread pool problem?

Glyn Normington glyn.normington at gmail.com
Fri Aug 31 12:10:41 EDT 2007


I wrote the attached testcase to try out the concurrency utilities on a dual
processor system and found that the fixed thread pool sometimes schedules
threads serially. I've reproduced this behaviour on a 4-way system and on
Java 5 and Java 6 with a couple of different JVMs. I've also spent a fair
amount of time analysing thread dumps to try to understand the behaviour.
Unfortunately, my current employer doesn't like me reading GPL code (but
let's not get into that here!), so the only source code I've found for the
concurrency utilities is some early "public domain" code, so I haven't been
able to get much further in analysis.

To reproduce the behaviour, execute:

java -jar life.jar

and watch the CPU utilisation using a system monitor. On a dual or quad CPU
system, this stays at around one processor's worth.

The source code is included in the jar, but snippets of the crucial class
follow at the end of this post. To highlight the undesirable behaviour,
uncomment the line marked [A] and you'll find that all CPUs run at 100%. But
if you comment out [A] again and uncomment the line marked [B], then only
one processor is driven to 100% on average. I say on average because, on the
systems I've tried, the hot thread seems to move between CPUs from time to
time. It's a mystery to me why moving the infinite loop after the statement:

for (Generation p : list) {

should make any difference. My guess is that this simply affects the timing.
(Yes, I did try writing out the for loop in the older syntax in case there
was some surprise synchronization and the behaviour was unchanged.)

Thoughts? Simple coding slip??

Glyn

...
public class ConcurrentGenerator implements Generator {

    private static final int PROCS = Runtime.getRuntime
().availableProcessors();

    @GuardedBy("this")
    private Generation current;

    @GuardedBy("this")
    private int prevIndex = 0;

    @GuardedBy("previous[i]")
    private List<?> previous[] = new ArrayList<?>[PROCS];

    private final int dim;
    private final Rule rule;

    private volatile boolean repeated = false;

    private static final ExecutorService exec = Executors.newFixedThreadPool
(PROCS);

    ...

    private class Scanner implements Callable<Boolean> {
        private Generation curGen;
        private final ArrayList<Generation> list;
        @SuppressWarnings("unchecked")
        public Scanner(int i, Generation cur) {
            list = (ArrayList<Generation>) previous[i];
            try {
                curGen = (Generation)cur.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
        }
        public Boolean call() throws Exception {
            boolean rep = false;
            synchronized (list) {
                // while (list != null) {} // produces 2x100% CPU on a dual
processor system [A]
                for (Generation p : list) {
                    // while (list != null) {} // only produces 100% CPU on
a dual processor system [B]
                    if (curGen.equals(p)) {
                        rep = true;
                    }
                }
            }
            return rep;
        }
    }

    @SuppressWarnings("unchecked")
    private void scheduleRepeatCheck() {
        Future<?> futures[] = new Future<?>[PROCS];
        for (int i = 0; i < PROCS; i++) {
            futures[i] = exec.submit(new Scanner(i, current));
        }
        for (int i = 0; i < PROCS; i++) {
            try {
                repeated = repeated || ((Future<Boolean>)futures[i]).get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }

  ...
-------------- next part --------------
An HTML attachment was scrubbed...
URL: /pipermail/attachments/20070831/8ad91233/attachment-0001.html 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: life.jar
Type: application/x-java-archive
Size: 14168 bytes
Desc: not available
Url : /pipermail/attachments/20070831/8ad91233/attachment-0001.bin 


More information about the Concurrency-interest mailing list