Home > database >  Synchronize on List
Synchronize on List

Time:10-20

Suppose I have this code block:

List<Integer> lst = Collections.synchronizedCollection(new ArrayList<>());

And I have the following two methods:

public Integer returnFirst() {
  lst.get(0);
}

public void iterate() {
synchronized(lst) {
     Iterator i = lst.iterator();
     while (i.hasNext()) {
       System.out.println(i);
     }
   }
}

Supposed that a thread calls iterate(), then another thread calls returnFirst(). Would returnFirst() be blocked since you are synchronizing on the List object in iterate, and iterate is currently running?

CodePudding user response:

Yes, you're correct. returnFirst won't run until iterate is complete.

CodePudding user response:

Yes. Take a look at the SynchronizedCollection constructor amd SynchronizedList#get method:

        SynchronizedCollection(Collection<E> c) {
            this.c = Objects.requireNonNull(c);
            mutex = this;
        }
        public E get(int index) {
            synchronized (mutex) {return list.get(index);}
        }

You can see that the internal mutex used to control concurrent access is actually the object itself(mutex = this), this means that lst.get(0) and synchronized(LST) in your iterate() method compete for the same lock: the object itself.

In addition, your code will not compile, replace synchronizedCollection with synchronizedList.

Simple code test:

    public static void main(String[] args) throws InterruptedException {
        List<Integer> list = Collections.synchronizedList(new ArrayList<>());
        list.add(1);
        new Thread(() -> {
            try {
                synchronized(list) {
                    Thread.sleep(5000);
                    Iterator i = list.iterator();
                    while (i.hasNext()) {
                        System.out.println(i.next());
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        Thread.sleep(100);
        new Thread(() -> {
            // It will block for 5 seconds and then output
            System.out.println(list.get(0));
        }).start();
    }
  • Related