1

There are two threads A and B. A keeps writing to an ArrayList and B keeps reading from it. The following code is for reading the ArrayList and belongs to thread B.

The issue with this code is that sometimes both of the IF statements becomes true which should not be possible. First IF is there to ensure that list is not read beyond its size. Second IF is not a part of actual code. I have put it just for verification purposes. As you can see in the Output below, size of the list is greater than writeNext variable, I don't understand why this returns null. And yes, if I place a print statement or a a very small delay just after first IF, everything works fine. Please remember that there is just one thread that writes into the ArrayList, so issue should not be related to synchronization.

 public void run() {// thread B

public class WriteTicksToFile implements Runnable, Serializable {

    int writeNext = 0;

    @Override
    public void run() {

        while (true) {

            // read till writeNext is equal to ArrayList.size()-1 i.e. the last index
            if (writeNext < TickData.getCompleteTickList().size()) {

                // System.out.println(TickData.getCompleteTickList().size()+" "+writeNext);
                if (TickData.getCompleteTickList().get(writeNext) == null) {

                    System.out.println("ListSize: " + TickData.getCompleteTickList().size() + " " + "Read@Index: " + writeNext);

                }// if ends

                // write element to file.
                writeTick(TickData.getCompleteTickList().get(writeNext));
                writeNext++;
            }// if ends
        }// while ends
    }
}

Output:

Number of symbols found: 19
Market Opening time: 81500
Market Closing time: 235900
Current Time: 203931
Waiting for market to open...
Market Opened @ 203931
ListSize: 15876 Read@Index: 15875
ListSize: 15877 Read@Index: 15876
azurefrog
  • 10,785
  • 7
  • 42
  • 56
Akki
  • 112
  • 12
  • If there is a separate thread writing into the list, then it might just write into it right while the reading thread is between the two `if` statements. So I would guess it actually is related to synchronization afterall. – Ingo Bürk Jun 22 '14 at 20:52
  • @IngoBürk Agreed; I don't see any mechanism for ensuring exclusive access to the list. – David Ehrmann Jun 22 '14 at 20:53
  • Show us the code used by Thread A. – fajarkoe Jun 22 '14 at 20:56
  • Possibly, the size of the list is incremented, before the element is available through the get() method. Whenever there are two threads working on one object, you should ensure proper synchronization. – Udo Klimaschewski Jun 22 '14 at 20:58
  • 1
    Take a look at http://stackoverflow.com/questions/11079210/thread-safe-circular-buffer-in-java. There are a number of fast solutions to this problem. – sfjac Jun 22 '14 at 20:59
  • I try to read only after making sure that writeNext is less than the size of the ArrayList (first IF). So, once size has been returned as, for example, 25, there must be some element at 24th. position which would be the last valid index. Once, first IF is ture, second IF must not be true. – Akki Jun 22 '14 at 21:00
  • @UdoKlimaschewski: Is this possible that ArrayList returns increased size of the list before it has actually added the element? – Akki Jun 22 '14 at 21:02
  • @sfjac: I can use Collections.synchronizedList() to make it work correctly. I am just trying to figure what is the problem here. Synchronization problems shouldn't occur when there is only one thread writing. – Akki Jun 22 '14 at 21:05
  • If you don't use explicitly thread-safe operations/data structures (which ArrayList isn't) you have no guarantees of consistency. The Java memory model allows memory writes to be re-ordered in ways that you won't be able to predict, even in apparently simple cases like this. You *will* encounter situations like this if you don't do things the right way. Basic rule of thumb is if you have two threads accessing the same data *in any way* (except all reading I guess), you must use threadsafe operations. – CupawnTae Jun 22 '14 at 21:10
  • @CupawnTae: Agreed. But still, Is this possible that ArrayList returns increased size of the list before it has actually added the element? – Akki Jun 22 '14 at 21:16
  • @Akki In Java 7 this it is really the case that first the size is increased and then the added object is placed into the new slot. I had a short look at the sources at http://docjar.com/html/api/java/util/ArrayList.java.html. There is no synchronization and therefore there is a - maybe very little - chance to hit an ArrayList just between these two calls. Using some synchronized wrapper as sfjac explained seems the best opportunuíty. – blafasel Jun 22 '14 at 21:25
  • ...and even if it *were* done the other way around, the memory writes could be reordered by the JVM or the CPU so that the size increment actually happened first – CupawnTae Jun 22 '14 at 21:26
  • @blafasel This is what I see in JDK ArrayList code. public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true;} size is incremented (size++, post increment) after element(e) is assigned to array( elementData ). – Akki Jun 23 '14 at 13:20

1 Answers1

4

Please remember that there is just one thread that writes into the ArrayList, so issue should not be related to synchronization.

That is simply not true according to the javadoc for ArrayList:

Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.

You have multiple threads accessing an ArrayList concurrently and one of them is modifying the list structurally.

Brett Okken
  • 6,210
  • 1
  • 19
  • 25