I'm trying to improve my understanding of the scope of the lock issued during a synchronized call.
Eg:
class CopyOnReadList<T> {
private final List<T> items = new ArrayList<T>();
public void add(T item) {
items.add(item);
}
public List<T> makeSnapshot() {
List<T> copy = new ArrayList<T>();
synchronized (items) {
// Make a copy while holding the lock.
for (T t : items) copy.add(t);
}
return copy;
}
}
(Code lovingly borrowed from this excellent answer)
In this code snippet, can one thread call add while another is calling makeSnapshot?. Ie., does the lock created by synchronized (items) affect all attempted reads to items, or only those attempted through the makeSnapshot() method?
The original post actually used a synchonized lock in the add method:
public void add(T item) {
synchronized (items) {
// Add item while holding the lock.
items.add(item);
}
}
What is the side effect of removing this?
It affects only those attempted in makeSnapshot() or, more generally, any other method that has synchronized(items) block (it means that it will try to aquire lock on items object and block until it's possible).
The side effect of removing synchronized block from add() method is that add() will not try to synchronize on items object, and therefore will allow concurrent modifications, including while makeSnapshot() is executing.
Without synchronize in add() you can have other threads add elements to items collection WHILE the snapshot is being made.
In this code snippet, can one thread call add while another is calling
makeSnapshot?
Certainly - and either one of the methods can then fail with a ConcurrentModificationException, or the content of the list may be corrupted.
does the lock created by synchronized (items) affect all attempted
reads to items, or only those attempted through the makeSnapshot()
method?
Neither. The lock has not effect whatsoever on the behaviour of the object items, only on blocks or methods that snychronize on it - namely to ensure that no two threads can execute any of those blocks or methods at the same time.
can one thread call add while another is calling makeSnapshot?
Yes. synchronized makes sure that any other thread can't enter another block of code which is also synchronized, on the same object (the CopyOnReadList, in this case). Since you have not synchronized the add method, several threads can call add concurrently, even if one thread is executing makeSnapshot.
By removing the synchronized on the add method, you've made the code non-threadsafe, since ArrayList is not thread-safe.
The rule of thumb is: every access (read or write) to a shared mutable state must be synchronized on the same lock.
Related
I need to solve this problem. I have console app in which I am inserting some String values. The console app is still running, user can add more and more entries and every 1 minute, there should be another Thread which will print some List statistic (e.g. size etc.). When I use Main Thread for user's console and different Thread for counting and printing this statistic data to the console (both working with the same List). It is enough to use:
List<String> list = Collections.synchronizedList(new ArrayList<>());
Or I need to user volatile and access the List in the synchronized block as well?
Thank you!
It depends what you want to do with the list.
Collections.synchronizedList(...) simply wraps every method with a synchronized block, synchronizing on itself. The synchronization starts when the invoked method starts executing, and stops when it stops executing.
Notionally, it the list is wrapped like this:
class SynchronizedList<T> implements List<T> {
private List<T> delegate;
#Override public int size() {
synchronized (this) {
return delegate.size();
}
}
// ...
}
As such, doing simple things like list.size(), list.add(...), list.get(...) don't require any further synchronization.
However, if you want to do more complex things, for example iterating the list, yes, you need additional synchronization:
synchronized (list) {
for (String s : list) { ... }
}
This is because the synchronization stops as soon as the hidden call to list.iterator() completes; hence, other threads would be able to modify the list while you are iterating.
My program looks like this:
public class Main {
private static ArrayList<T> list;
public static void main(String[] args) {
new DataListener().start();
new DataUpdater().start();
}
static class DataListener extends Thread {
#Override
public void run() {
while(true){
//Reading the ArrayList and displaying the updated data
Thread.sleep(5000);
}
}
}
static class DataUpdater extends Thread{
#Override
public void run() {
//Continuously receive data and update ArrayList;
}
}
}
In order to use this ArrayList in both threads, I know two options:
To make the ArrayList volatile. However I read in this article that making variables volatile is only allowed if it "Writes to the variable do not depend on its current value." which I think in this case it does (because for example when you do an add operation on an ArrayList, the contents of the ArrayList after this operation depend on the current contents of the ArrayList, or doesn't it?). Also the DataUpdater has to remove some elements from the list every now and then, and I also read that editing a volatile variable from different threads is not possible.
To make this ArrayList a synchronized variable. However, my DataUpdater will continuously update the ArrayList, so won't this block the DataListener from reading the ArrayList?
Did I misunderstand any concepts here or is there another option to make this possible?
Volatile won't help you at all. The meaning of volatile is that changes made by thread A to a shared variable are visible to thread B immediately. Usually such changes may be in some cache visible only to the thread that made them, and volatile just tells the JVM not to do any caching or optimization that will result in the value update being delayed.
So it is not a means of synchronization. It's just a means of ensuring visibility of change. Moreover, it's change to the variable, not to the object referenced by that variable. That is, if you mark list as volatile, it will only make any difference if you assign a new list to list, not if you change the content of the list!
Your other suggestion was to make the ArrayList a synchronized variable. There is a misconception here. Variables can't be synchronized. The only thing that can be synchronized is code - either an entire method or a specific block inside it. You use an object as the synchronization monitor.
The monitor is the object itself (actually, it's a logical part of the object that is the monitor), not the variable. If you assign a different object to the same variable after synchronizing on the old value, then you won't have your old monitor available.
But in any case, it's not the object that's synchronized, it's code that you decided to synchronize using that object.
You can therefore use the list as the monitor for synchronizing the operations on it. But you can not have list synchronized.
Suppose you want to synchronize your operations using the list as a monitor, you should design it so that the writer thread doesn't hold the lock all the time. That is, it just grabs it for a single read-update, insert, etc., and then releases it. Grabs it again for the next operation, then releases it. If you synchronize the whole method or the whole update loop, the other thread will never be able to read it.
In the reading thread, you should probably do something like:
List<T> listCopy;
synchronized (list) {
listCopy = new ArrayList(list);
}
// Use listCopy for displaying the value rather than list
This is because displaying is potentially slow - it may involve I/O, updating GUI etc. So to minimize the lock time, you just copy the values from the list, and then release the monitor so that the updating thread can do its work.
Other than that, there are many types of objects in the java.util.concurrent package etc. that are designed to help in situations like this, where one side is writing and the other is reading. Check the documentation - perhaps a ConcurrentLinkedDeque will work for you.
Indeed, none of the two solutions is sufficient. You actually need to synchronize the complete iteration on the arraylist, and every write access to the arraylist:
synchronized(list) {
for (T t : list) {
...
}
}
and
synchronized(list) {
// read/add/modify the list
}
make the ArrayList volatile.
You can't make an ArrayList volatile. You can't make any object volatile. The only things in Java that can be volatile are fields.
In your example, list is not an ArrayList.
private static ArrayList<T> list;
list is a static field of the Main class.
The volatile keyword only matters when one thread updates the field, and another thread subsequently accesses the field.
This line updates the list, but does not update the volatile field:
list.add(e);
After executing that line, the list has changed, but the field still refers to the same list object.
An object has two synchronized list attributes (listA and listB) and a method called add(...) which adds an element into these two lists. My question is: should this method be synchronized if it is called from differnt threads?
can problems occur when the method SwingUtilities.invokeLater is used inside synchronozed methods?
when using synchronized(this){..code...}, is in this case only the code-block or all methods of the object (this) blocked when a thread access the code-block?
Actually synchronized methods are the same as synchronized(this){} because "this" refers to the object and this one will provide the lock. If you use any of these synchronizations and one thread calls a synchronized method, the other threads cannot access all synchronized methods of the object. if you want to avoid this, create a new variable to provide the lock instead of synchronizing the method. For instance
public void add(String s)
{
private Object block = new Object();
synchronized(block)
{
listA.add(s);
listB.add(s);
}
}
public int count()
{
return listA.size(); //returns the most recent listA update size
// method can be accessed while another thread adds elements to listA
}
An object has two synchronized list attributes (listA and listB) and a
method called add(...) which adds an element into these two lists. My
question is: should this method be synchronized if it is called from
differnt threads?
That depends. If you want the order of the elements in listA and listB to be the same, then yes, you should synchronize when you're adding to both lists. Otherwise, if would be possible that you get things in this order:
Thread A adds element to listA
Thread B adds element to listA
Thread B adds element to listB
Thread A adds element to listB
-
can problems occur when the method SwingUtilities.invokeLater is used
inside synchronozed methods?
No, there's no problem with that. I don't really see what problem you think that you could get.
when using synchronized(this){..code...}, is in this case only the
code-block or all methods of the object (this) blocked when a thread
access the code-block?
It blocks all non-static methods that are synchronized (because that means the same as synchronized (this) and all code blocks that use synchronized (this).
In addition, it blocks any code in other classes that synchronizes on the same object.
Static methods and non-synchronized methods do not block while you are inside synchronized (this).
This is my first time using the synchronized keyword, so I am still unsure of how it exactly works. I have a list that I want to be accessed by multiple threads so I do this:
players = Collections.synchronizedList(new ArrayList<Player>(maxPlayers));
Now, I want to make sure that I am not calling players.add() at the same time as players.get(), so I think i should use synchronized statements (methods A and B could be called at the same time):
public void A() {
synchronized(players) {
players.add(new Player());
}
}
public void B(String msg) {
synchronized(players) {
for(int i = 0;i<players.size();i++) {
players.get(i).out.println(msg);
}
}
}
Is this the correct procedure? If not, what should I do instead?
Provided you only access the list through the object returned by synchronizedList then access should be thread-safe, though note that you may need to used synchronized blocks for compound actions like iterating through the list or making actions and decisions based on multiple calls into the list (for example, getting a value making a decision then adding a value).
So in your example A() doesn't need the synchronized block, but B() might if you don't want the list to be changed or be read by some other thread during the iteration. (In fact, by using the counter to iterate it is needed to prevent a race condition between the loop termination condition and another thread removing an item; other ways of iterating might not have this issue though).
I am enhancing an existing algorithm that consists of multiple independent steps to use concurrent tasks. Each of the tasks will create multiple objects to hold its results. In the end, I would like to have a list of all the results to return from the controlling method. At the moment, my code looks something like that
private final ExecutorService pool = ...;
// A single task to be performed concurrently with other tasks.
private class WorkHorse implements Callable<Void> {
private final Collection<X> collect;
public WorkHorse(Collection<X> collect, ...) {
this.collect = collect;
}
public Void call() {
for (...) {
// do work
synchronized (this.collect) {
this.collect.add(result);
}
}
return null;
}
}
// Uses multiple concurrent tasks to compute its result list.
public Collection<X> getResults() {
// this list is supposed to hold the results
final Collection<X> collect = new LinkedList<X>();
final List<WorkHorse> tasks = Arrays.asList(
new WorkHorse(collect, ...), new WorkHorse(collect, ...), ...);
this.pool.invokeAll(tasks);
// ## A ##
synchronized (collect) {
return collect;
}
}
Do I actually need the synchronized at "## A ##" to enforce a happens-before relationship with the modifying operations in the worker tasks? Or can I rely on all write operations to have happened after invokeAll returns and be visible to the controlling thread? And is there any reason, why I should not return the results collection from within its own synchronized block?
No, you don't need that. The documentation of invokeAll states that all jobs should be done when it returns. So there should be no further access to collect when you reach the return statement.
You don't need the second synchronized if you have the first one in there. As Zed notes, invokeAll() will block until all tasks have completed. Meanwhile, the synchronization around add() will ensure that the changes to the collection are visible to all threads, including the original calling thread.
As for whether you need the first one (which you didn't ask) -- I tried removing both synchronized blocks and couldn't actually get it to fail, but having it in there is probably the safer bet. According to the javadoc for LinkedList:
If multiple threads access a
LinkedList concurrently, and at least
one of the threads modifies the list
structurally, it must be
synchronized externally.
The other "2nd-generation" Collection implementations have similar warnings.
Note by the way that there's nothing magic about synchronizing on the collection itself. You could declare a separate mutex (any old Object would do) in the outer class, or synchronize on the outer class instance, and that would work just as well, so long as all WorkHorses synchronize on the same thing.