1

I have a problem in queue threads with ThreadPoolExecutor Sometimes it overlaps the same task.

Here is my code:

int threadSize = 3;
int maxThreadSize = 3;
int TTL = 10;
int queueSize = map.size();


ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(queueSize);
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(threadSize, maxThreadSize, TTL, TimeUnit.SECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy());

for(final Entry<String,String> entry : map.entrySet()){
   threadPool.execute(new Runnable() {                              
      @Override
      public void run() {
         //…do something
         System.out.println(entry.getKey + " : " + entry.getValue);                     
      }
   });
}

example

If map have a pair of key and value like shown below.

Key : Values

"1" : "AAA"

"2" : "BBB"

...

"26" : "ZZZ"

My result sometimes can be…

1 : AAA

2 : BBB

3 : CCC

3 : CCC

4 : DDD

...

25 : YYY

It's double "3 : CCC" and have no "26 : ZZZ". How can I solve this problem?

[Edit] this problem happen randomly not only "3 : CCC"

sometimes it happen to other entry

sometimes the problem doesn't happen

when one entry has overlapped is mean one other will not be printed

so I guess it is my queing problem

Gornie
  • 31
  • 5

2 Answers2

0

What about the map you are using? Maybe it fills somewhere you didn't noticed?

Try PriorityQueue if you need to see ordered elements despite of insertion order.

Vladimir Kishlaly
  • 1,872
  • 1
  • 16
  • 26
0

When you iterate a Map.entrySet, it does not have to return an immutable Entry object for each entry each time. It could return the same Entry object over and over during the iteration, modifying its fields, or it could already have an allocated Entry object for each key-value mapping in the map, but modify the existing Entry objects if you later modify the map. This means the Entry objects may not have the same key and value by the time they are used in the Runnables as at the time you create each Runnable.

Try creating a separate immutable Entry object for use by each Runnable:

for (Entry<String,String> entry1 : map.entrySet()) {
    final Entry<String,String> entry = new AbstractMap.SimpleImmutableEntry<>(entry1);
    /* ... */
}

Or pull the key and value into separate variables for use in the Runnable:

for (Entry<String,String> entry : map.entrySet()) {
    final String key = entry.getKey();
    final String value = entry.getValue();
    /* ... */
}
Boann
  • 48,794
  • 16
  • 117
  • 146
  • I am not sure that's how it works. `entry` is final so it can't be modified and should be correctly handled by the JVM, see [this](http://stackoverflow.com/questions/3911167/how-does-final-int-i-work-inside-of-a-java-for-loop). – Giovanni Botta Aug 10 '15 at 13:09
  • @GiovanniBotta `entry` being final prevents the variable being reassigned. It doesn't and can't do anything to prevent the object pointed to by the variable from being modified. – Boann Aug 10 '15 at 13:11
  • Yes, if the element itself is being modified. There is no evidence of this because the OP is seeing duplicate keys. If the map was modified that would cause `ConcurrentModificationException`, so the same entry could never be used for two different keys without that happening. – Giovanni Botta Aug 10 '15 at 13:16
  • @GiovanniBotta Modifications to the map outside the loop but before the `Runnable`s ran wouldn't cause a `ConcurrentModificationException`, nor would the iterator returning the same modified `Entry` object over and over. However, I'm now less convinced this is the cause, because neither `HashMap` nor `TreeMap` currently seems to re-use the `Entry` objects during iteration (I could have sworn they used to, or what else am I confusing it with...?) and you are right that modifying the map ought not to cause *duplicate* key-value pairs in the output (just wrong values). Question needs more code! – Boann Aug 10 '15 at 13:44
  • As per the [docs](http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html): "For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception." So the exception would definitely be thrown if that was happening. You can easily verify that. – Giovanni Botta Aug 10 '15 at 14:51
  • @GiovanniBotta I never said I thought the map was being modified during iteration. Obviously it isn't. I don't know why you brought that idea up. – Boann Aug 10 '15 at 15:04
  • I'm sure this will change nothing. if this problem is cause of that final variable, it will be compile error or my result should be 26 "1 : AAA". I've done it on your advice, but result is still the same. (cry) – Gornie Aug 10 '15 at 17:53
  • @Gornie There wouldn't be any compilation error because it is perfectly legal for objects pointed to by final variables to be modified. Anyway, sorry it didn't help. If you provide an [MCVE](https://stackoverflow.com/help/mcve) of the problem it's more likely that someone will be able to help you. – Boann Aug 10 '15 at 18:10
  • Oh I thought that's what you meant because that's the only way I thought the same entry could be somehow reused. All good. – Giovanni Botta Aug 11 '15 at 21:16