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();
}