0
for (int i = 0; i < 3; i++) {
    list.add("test" + i);
}

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (list) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add("test3");
        }
    }
});

thread.start();

synchronized (list) {
    System.out.println(list);
}

What I'm not understanding right now is, the printout doesn't contain "test3". Shouldn't synchronizing list during the thread halt the println at the end?

So they should be in order of:

Thread.sleep();
list.add("test3");
println(list);

What's going on?

Justin Q.
  • 13
  • 2
  • [About synchronized in Java](https://stackoverflow.com/questions/1085709/what-does-synchronized-mean). – user202729 Mar 04 '18 at 07:22
  • > "No, synchronized will give access in any order" -- [source](https://stackoverflow.com/questions/1802830/ensure-java-synchonized-locks-are-taken-in-order). – user202729 Mar 04 '18 at 07:23

2 Answers2

3

Shouldn't synchronizing list during the thread halt the println at the end?

That would only be true if the second thread's run() method's execution (and in particular the execution of the synchronized (list) statement within it) started before the synchronized (list) statement of the main thread is executed.

Calling thread.start(); before synchronized (list) {System.out.println(list);} does not guarantee the second thread will start running before synchronized (list) {System.out.println(list);} is executed.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • What ways could I determine order of execution with multiple threads to ensure there aren't concurrent modification issues? For example, if I was looping through an ArrayList and within that ArrayList, it's to send a packet. The packet returns Broken Pipe, and the "Object" within the ArrayList is deleted by the "Object" thread. How can I ensure that the loop completes before removing the Object that sent a Broken Pipe? – Justin Q. Mar 04 '18 at 07:32
  • @JustinQuach Your use case is not clear enough, but perhaps you can use some concurrent collection (such as CopyOnWriteArrayList). – Eran Mar 04 '18 at 07:44
  • You can use classes like `Condition` or a `ReadWriteLock` to wait for a thread. If your use case is simpler then there are also [concurrent collections](https://docs.oracle.com/javase/tutorial/essential/concurrency/collections.html) – M. le Rutte Mar 04 '18 at 07:53
0

What I'm not understanding right now is, the printout doesn't contain "test3". Shouldn't synchronizing list during the thread halt the println at the end?

That would imply that the Thread you started would get the lock before the main thread. There is no way to guarantee that in Java. In fact, it seemed to work the other way round, main thread takes lock before the second thread, blocking the second thread from taking the lock.

You could try to use the wait/notify mechanism to ensure the main thread is waiting for the other thread to terminate: import java.util.ArrayList;

    for (int i = 0; i < 3; i++) {
        list.add("test" + i);
    }

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (list) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                list.add("test3");
                // Notify the main thread
                list.notify();
            }
        }
    });

    thread.start();

    synchronized (list) {
        try {
            // wait for the other thread for a specified time to terminate
            // this will temporary release the lock for the second thread.
            list.wait(5000);
        } catch (InterruptedException e) {
            // see above..
            e.printStackTrace();
        }
        System.out.println(list);
    }
Dorian Gray
  • 2,913
  • 1
  • 9
  • 25