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.
Related
How do I lock a data structure (such as List) when someone is iterating over it?
For example, let's say I have this class with a list in it:
class A{
private List<Integer> list = new ArrayList<>();
public MyList() {
// initialize this.list
}
public List<Integer> getList() {
return list;
}
}
And I run this code:
public static void main(String[] args) {
A a = new A();
Thread t1 = new Thread(()->{
a.getList().forEach(System.out::println);
});
Thread t2 = new Thread(()->{
a.getList().removeIf(e->e==1);
});
t1.start();
t2.start();
}
I don't have a single block of code that uses the list, so I can't use synchronized().
I was thinking of locking the getList() method after it has been called but how can I know if the caller has finished using it so I could unlock it?
And I don't want to use CopyOnWriteArrayList because of I care about my performance;
after it has been called but how can I know if the caller has finished using it so I could unlock it?
That's impossible. The iterator API fundamentally doesn't require that you explicitly 'close' them, so, this is simply not something you can make happen. You have a problem here:
Iterating over the same list from multiple threads is an issue if anybody modifies that list in between. Actually, threads are immaterial; if you modify a list then interact with an iterator created before the modification, you get ConcurrentModificationException guaranteed. Involve threads, and you merely usually get a CoModEx; you may get bizarre behaviour if you haven't set up your locking properly.
Your chosen solution is "I shall lock the list.. but how do I do that? Better ask SO". But that's not the correct solution.
You have a few options:
Use a lock
It's not specifically the iteration that you need to lock, it's "whatever interacts with this list". Make an actual lock object, and define that any interaction of any kind with this list must occur in the confines of this lock.
Thread t1 = new Thread(() -> {
a.acquireLock();
try {
a.getList().forEach(System.out::println);
} finally {
a.releaseLock();
}
});
t1.start();
Where acquireLock and releaseLock are methods you write that use a ReadWriteLock to do their thing.
Use CopyOnWriteArrayList
COWList is an implementation of java.util.List with the property that it copies the backing store anytime you change anything about it. This has the benefit that any iterator you made is guaranteed to never throw ConcurrentModificationException: When you start iterating over it, you will end up iterating each value that was there as the list was when you began the iteration. Even if your code, or any other thread, starts modifying that list halfway through. The downside is, of course, that it is making lots of copies if you make lots of modifications, so this is not a good idea if the list is large and you're modifying it a lot.
Get rid of the getList() method, move the tasks into the object itself.
I don't know what a is (the object you call .getList() on, but apparently one of the functions that whatever this is should expose is some job that you really can't do with a getList() call: It's not just that you want the contents, you want to get the contents in a stable fashion (perhaps the method should instead have a method that gives you a copy of the list), or perhaps you want to do a thing to each element inside it (e.g. instead of getting the list and calling .forEach(System.out::println) on it, instead pass System.out::println to a and let it do the work. You can then focus your locks or other solutions to avoid clashes in that code, and not in callers of a.
Make a copy yourself
This doesn't actually work, even though it seems like it: Immediately clone the list after you receive it. This doesn't work, because cloning the list is itself an operation that iterates, just like .forEach(System.out::println) does, so if another thread interacts with the list while you are making your clone, it fails. Use one of the above 3 solutions instead.
I am not sure how to properly use the Collections.synchronizedList() implementation.
I have these two:
public synchronized static List<CurrencyBox> getOrderList() {
return Collections.synchronizedList(orderList);
}
and
public static List<CurrencyBox> getOrderList() {
return Collections.synchronizedList(orderList);
}
So as far as I understood, synchronizedList really returns the orderList and not a copy, correct?
So If I want to gurantee atomic operations, like add and remove, which of the implementation above is correct?
And does something maybe changes with Java9? Or is it still the way to go or have you any other suggestion?
Thank you
Without context it's a bit hard to tell, from the snippets provided neither give you guaranteed atomic operations.
The documentation states:
Returns a synchronized (thread-safe) list backed by the specified
list. In order to guarantee serial access, it is critical that all
access to the backing list is accomplished through the returned list.
So even if you synchronize the method the best you'll get is a guarantee that no two objects are creating the synchronized list at the same time.
You need to wrap the original orderList with Collections.synchronizedList to begin with and return the stored result of that each time.
private static List<CurrencyBox> orderList = Collections.synchronizedList(new ArrayList<CurrencyBox>());
public static List<CurrencyBox> getOrderList() {
return orderList
}
A synchronized list only synchronized methods of this list.
It means a thread won't be able to modify the list while another thread is currently running a method from this list. The object is locked while processing method.
As an example, Let's say two threads run addAllon your list, with 2 different lists (A=A1,A2,A3, B=B1,B2,B3) as parameter.
As the method is synchronized, you can be sure those lists won't be merged randomly like A1,B1,A2,A3,B2,B3
You don't decide when a thread handover the process to the other thread so you can either get A1,A2,A3,B1,B2,B3 or B1,B2,B3,A1,A2,A3.
Credit : jhamon
I have several threads trying to increment a counter for a certain key in a not thread-safe custom data structure (which you can image to be similiar to a HashMap). I was wondering what the right way to increment the counter in this case would be.
Is it sufficient to synchronize the increment function or do I also need to synchronize the get operation?
public class Example {
private MyDataStructure<Key, Integer> datastructure = new CustomDataStructure<Key, Integer>();
private class MyThread implements Runnable() {
private synchronized void incrementCnt(Key key) {
// from the datastructure documentation: if a value already exists for the given key, the
// previous value will be replaced by this value
datastructure.put(key, getCnt(key)+1);
// or can I do it without using the getCnt() function? like this:
datastructure.put(key, datastructure.get(key)+1));
}
private synchronized int getCnt(Key key) {
return datastructure.get(key);
}
// run method...
}
}
If I have two threads t1, t2 for example, I would to something like:
t1.incrementCnt();
t2.incrmentCnt();
Can this lead to any kind of deadlock? Is there a better way to solve this?
Main issue with this code is that it's likely to fail in providing synchronization access to datastructure, since accessing code synchronizing on this of an inner class. Which is different for different instances of MyThread, so no mutual exclusion will happen.
More correct way is to make datastructure a final field, and then to synchronize on it:
private final MyDataStructure<Key, Integer> datastructure = new CustomDataStructure<Key, Integer>();
private class MyThread implements Runnable() {
private void incrementCnt(Key key) {
synchronized (datastructure) {
// or can I do it without using the getCnt() function? like this:
datastructure.put(key, datastructure.get(key)+1));
}
}
As long as all data access is done using synchronized (datastructure), code is thread-safe and it's safe to just use datastructure.get(...). There should be no dead-locks, since deadlocks can occur only when there's more than one lock to compete for.
As the other answer told you, you should synchronize on your data structure, rather than on the thread/runnable object. It is a common mistake to try to use synchronized methods in the thread or runnable object. Synchronization locks are instance-based, not class-based (unless the method is static), and when you are running multiple threads, this means that there are actually multiple thread instances.
It's less clear-cut about Runnables: you could be using a single instance of your Runnable class with several threads. So in principle you could synchronize on it. But I still think it's bad form because in the future you may want to create more than one instance of it, and get a really nasty bug.
So the general best practice is to synchronize on the actual item that you are accessing.
Furthermore, the design conundrum of whether or not to use two methods should be solved by moving the whole thing into the data structure itself, if you can do so (if the class source is under your control). This is an operation that is confined to the data structure and applies only to it, and doing the increment outside of it is not good encapsulation. If your data structure exposes a synchronized incrementCnt method, then:
It synchronizes on itself, which is what you wanted.
It can use its own private fields directly, which means you don't actually need to call a getter and a setter.
It is free to have the implementation changed to one of the atomic structures in the future if it becomes possible, or add other implementation details (such as logging increment operations separately from setter access operations).
I have a List read (iterated through) many times and by multiple threads but updated rarely (reads are more than 50,000 times more numerous). EDIT: in fact, an array would suffice in this case, instead of a List.
When the list is updated, it's simply replaced with a different version (there are no add() or remove() calls).
A CopyOnWriteArrayList avoid the disadvantages of a synchronized list but I'm not sure that setting the list to the new value is atomic. I read this question as well.
To show some code. Consider the following as an attribute of a singleton Spring bean.
List<MyObject> myList; //the list read many times and concurrently.
//called by many threads
public void doStuff(){
for (MyObject mo : myList){
//do something
}
}
//called rarely. It's synchronized to prevent concurrent updates
//but my question is about thread-safety with regards to readers
public synchronized void updateList(List<MyObject> newList){ // newList is a CopyOnWriteArrayList<>();
myList = myNewList; //is this following statement executed atomically and thread-safe for readers?
}
Do I need to use a ReadWriteLock for achieve a thread-safe set?
The need for ReadWriteLock depends what you need to achieve.
If you want to ensure that reference is updated atomically you can use AtomicReference (or in your case enough to mark this reference as volatile), however if your goal is that updater thread should wait until all reading threads finish iterating over old list before updating the reference then ReadWriteLock is the way to go.
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.