Using synchronized lists - java

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).

Related

Synchronized ArrayList for two threads - write and read

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.

Which synchronize statements are unnecessary here?

First the code fragments...
final class AddedOrders {
private final Set<Order> orders = Sets.newConcurrentHashSet();
private final Set<String> ignoredItems = Sets.newConcurrentHashSet();
private boolean added = false;
public synchronized void clear() {
added = false;
}
public synchronized void add(Order order) {
added = orders.add(order);
}
public synchronized void remove(Order order) {
if (added) orders.remove(order);
}
public synchronized void ban(String item) {
ignoredItems.add(item);
}
public synchronized boolean has(Order order) {
return orders.contains(order);
}
public synchronized Set<Order> getOrders() {
return orders;
}
public synchronized boolean ignored(String item) {
return ignoredItems.contains(item);
}
}
private final AddedOrders added = new AddedOrders();
...
boolean subscribed;
int i = 10;
synchronized (added) {
while (!(subscribed = client.getSubscribedOrders().containsAll(added.getOrders())) && (i>0)) {
Helper.out("...order not subscribed yet (try: %d)", i);
Thread.sleep(200);
i--;
}
}
What I'd like to know...
Could someone point out which synchronized are not necessary?
Of course this is not the full code but assume that in the full project that all methods are called, and that some combinations of methods are called in the check value first, then modify style
added(the class) is accessed by multipleThreads
client is part of an external Server API, that I'm not entirely sure if it is Thread-Safe yet but I think it must be
ConcurrentHashSet is a google guava Class but it is based on ConcurrentHashMap apparently and the docs say it carries all the same concurrency guarantees.
But I don't really understand completely what those guarantees all are, even though I did some reading. Namely I know it's not ok to just check and set a value in a synchronized HashMap (without synchronizing on the synchronized Map using a synchronized block), however I do not know if you can do that in ConcurrentHashMap or not (without synchronizing on the ConcurrentHashMap using a synchronized block).
The only cases in your code where you really need synchronized are the ones where you test or update the added flag. You need the synchronized block to make sure that changes to the flag are visible across threads, and you also need to make sure that the added flag change is made in step with the change to the orders data structure. The synchronized keyword keeps another thread from barging in and doing something in between checking the flag and changing the data structure (the remove method could be broken like this if you remove the synchronization).
The code toward the end seems problematic because you're locking on the added object and then not letting go of the lock, there's not an opportunity for any other thread to make the changes that the thread is looking for. Although it looks like you're waiting for another object to change, so this criticism may be invalid. Sleeping with a lock held seems dangerous, though. This kind of thing is why Object#wait releases the lock it acquired.
Also note that since you're passing references out to the Orders set, code outside this class can add orders. You should do something to protect this internal data, like returning it wrapped in an immutableSet so callers can't make changes.
In general synchronization is used when you want to impose some granularity on changes, where you have 2 or more changes you want made together, without possibility of interleaving. An example is a check-then-act sequence where you execute some code that makes a change based on the value of something else, and you don't want some other thread to execute in between the check and the action (so the decision to act could be made, then the condition that allowed that action changes, so that the action could be invalid). If individual values are changed but they are unrelated, then you can make them volatile or use Atomic variables, and reduce the amount of locking you have to do.
It's a valid point that the synchronized keyword could be removed in cases like the clear method, where the only thing that changes is the added flag, which could be made volatile. The purpose of the added flag continues to elude me. Anything that enters a value that's already present can turn the flag back to false, it's not apparent that reasoning about any action based on what the current value of the flag makes any sense if this structure is getting modified concurrently.
Without knowing the exact context it's hard to say, but in general, classes created without considering their being used with multiple threads probably need to be reworked extensively before being used in a concurrent environment.

How do Synchronized Lists Work?

I am not sure I understand Synchronized Lists in Java. Suppose I have the following:
List<Integer> numbers = Collections.synchronizedList(new ArrayList<Integer>());
// Assumption: This is running on a separate thread
public void add() {
numbers.add(new Random().nextInt(100));
}
// This is also running on a separate thread
public void doSomething() {
synchronized(numbers) {
for (int i : numbers) {}
}
}
Basically, will the add() be able to add numbers to the list if doSomething() is invoked? What would happen if I instead used public synchronized void add() and public synchronized void doSomething()?
I am working on a UDP Socket Server, and I was going to store clients in an ArrayList. I would have multiple threads that can read, write, and modify this list. What should I be doing?
will the add() be able to add numbers to the list if doSomething() is invoked?
No, not until the thread invoking doSomething() leaves the synchronized block.
What would happen if I instead used public synchronized void add() and public synchronized void doSomething()?
Assuming these are the only places where the list is used, the effect would be the same. But you would syncronize on the object containing the list rather than synchronizing on the list itself.
Basically, all the accesses to a shared state must be synchronized on the same lock. You choose the lock that you prefer. Instead of using a sychronized list, or synchronized methods, you could use a concurrent collection like a CopyOnWriteArrayList.
This should work fine. According to the docs for Collections.synchronizedList, the list mutator methods (add(), etc.) synchronize on the list object itself. Since your iteration loop is also inside a synchronized block, all should be well.

Am I properly implementing Java's synchronized construct?

I'm kind of confused about how to implement synchronized blocks in Java.
Here is an example situation:
public class SlotWheel extends Thread implements ActionListener
{
private int currentTick; // This instance variable is modified in two places
private synchronized void resetCurrentTicks()
{
currentTick = 0;
}
private synchronized void incrementCurrentTicks()
{
++currentTick;
}
public void actionPerformed(ActionEvent e)
{
resetCurrentTicks();
}
}
While the program is running, it's possible that a user clicks a button which invokes actionPerformed which then calls resetCurrentTicks. At the same time, the running thread is calling incrementCurrentTicks on each loop iteration.
Because I'm still new to Java and programming, I'm not sure if my implementation is protecting currentTick from becoming corrupted.
I have this feeling that my implementation would only work if incrementCurrentTicks were to be called in actionPerformed and in the running thread, but because I'm manipulating currentTick from different methods, my implementation is wrong.
Looks ok.
See http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
It is not possible for two invocations of synchronized methods on the same object to interleave
Of course you should consider whether it is the GUI thread trying to mess with the ticks or not. In your simple case it's probably ok, but in a more complex case you might want to push the "work" out of the GUI thread.
Your instincts are correct. It is difficult to synchronize access to class properties consistently across multiple methods. Rather than attempting to do so, I would recommend you take a look at java.util.concurrent.atomic.AtomicInteger. It provides you with safe, concurrent access to the underlying property without writing and testing alot of boilerplate code.
Incorporating it into your code, you would end up with something like this:
public class SlotWheel extends Thread implements ActionListener {
private AtomicInteger currentTick = new AtomicInteger();
private void resetCurrentTicks() {
currentTick.set(0);
}
private void incrementCurrentTicks() {
currentTick.incrementAndGet();
}
public void actionPerformed(ActionEvent e)
{
resetCurrentTicks();
}
}
First off, Java guarantees that "scalar" values -- integers, chars, floats, etc -- are atomic in themselves in that you cannot simultaneously modify such a value and get a mixture of the two sources. You're guaranteed to get one value or the other of two "simultaneous" modifications. You can, however, get an inconsistent result from, eg, x++, since two threads may attempt to simultaneously increment x and possibly only one increment might occur. (OTOH, two threads simultaneously performing x = 7; will obviously not interfere with each other -- simultaneous access does not cause an explosion or anything.)
Next, understand that the synchronized keyword is used in two slightly different contexts -- as a method modifier and as a block modifier. There is some modest difference between the two.
When used as a block modifier you say synchronized(object_ref) {some block}. In this case the synchronized statement gets a lock on the object identified by object_ref and all other syncronized statements that might simultaneously attempt to execute referencing the same object will be held off while the current statement finishes its block.
When you use it as a method modifier, the function is the same except that, for a non-static method, the "this" object is the one that is locked, and the entire method is is "protected" by the lock.
(For a static method, on the other hand, the Class object is locked -- a slightly special case, equivalent to synchronized(ClassName.class){some block} as a synchronized block.)
It's important to understand that for two synchronized blocks or methods to be prevented from simultaneously executing they must be referencing, as their synchronizing object, the same object, not simply one of the same class.
You are correct, in that it is not safe. However, you can simply synchronize on any Object in scope, and remove "synchronized" from the method definition
public class MyThread {
private Object lock = new Object();
private int counter;
protected void threadMetod() {
synchronized (lock) {
counter++;
}
}
public void otherReset() {
synchronized (lock) {
counter = 0;
}
}
}

achieving synchronized addAll to a list in java

Updated the question.. please check secodn part of question
I need to build up a master list of book ids. I have multiple threaded tasks which brings up a subset of book ids. As soon as each task execution is completed, I need to add them to the super list of book ids. Hence I am planning to pass below aggregator class instance to all of my execution tasks and have them call the updateBookIds() method. To ensure it's thread safe, I have kept the addAll code in synchronized block.
Can any one suggest is this same as Synchronized list? Can I just say Collections.newSynchronizedList and call addAll to that list from all thread tasks? Please clarify.
public class SynchronizedBookIdsAggregator {
private List<String> bookIds;
public SynchronizedBookIdsAggregator(){
bookIds = new ArrayList<String>();
}
public void updateBookIds(List<String> ids){
synchronized (this) {
bookIds.addAll(ids);
}
}
public List<String> getBookIds() {
return bookIds;
}
public void setBookIds(List<String> bookIds) {
this.bookIds = bookIds;
}
}
Thanks,
Harish
Second Approach
So after below discussions, I am currently planning to go with below approach. Please let me know if I am doing anything wrong here:-
public class BooksManager{
private static Logger logger = LoggerFactory.getLogger();
private List<String> fetchMasterListOfBookIds(){
List<String> masterBookIds = Collections.synchronizedList(new ArrayList<String>());
List<String> libraryCodes = getAllLibraries();
ExecutorService libraryBookIdsExecutor = Executors.newFixedThreadPool(BookManagerConstants.LIBRARY_BOOK_IDS_EXECUTOR_POOL_SIZE);
for(String libraryCode : libraryCodes){
LibraryBookIdsCollectionTask libraryTask = new LibraryBookIdsCollectionTask(libraryCode, masterBookIds);
libraryBookIdsExecutor.execute(libraryTask);
}
libraryBookIdsExecutor.shutdown();
//Now the fetching of master list is complete.
//So I will just continue my processing of the master list
}
}
public class LibraryBookIdsCollectionTask implements Runnable {
private String libraryCode;
private List<String> masterBookIds;
public LibraryBookIdsCollectionTask(String libraryCode,List<String> masterBookIds){
this.libraryCode = libraryCode;
this.masterBookIds = masterBookIds;
}
public void run(){
List<String> bookids = new ArrayList<String>();//TODO get this list from iconnect call
synchronized (masterBookIds) {
masterBookIds.addAll(bookids);
}
}
}
Thanks,
Harish
Can I just say Collections.newSynchronizedList and call addAll to that list from all thread tasks?
If you're referring to Collections.synchronizedList, then yes, that would work fine. That will give you a object that implements the List interface where all of the methods from that interface are synchronized, including addAll.
Consider sticking with what you have, though, since it's arguably a cleaner design. If you pass the raw List to your tasks, then they get access to all of the methods on that interface, whereas all they really need to know is that there's an addAll method. Using your SynchronizedBookIdsAggregator keeps your tasks decoupled from design dependence on the List interface, and removes the temptation for them to call something other than addAll.
In cases like this, I tend to look for a Sink interface of some sort, but there never seems to be one around when I need it...
The code you have implemented does not create a synchronization point for someone who accesses the list via getBookIds(), which means they could see inconsistent data. Furthermore, someone who has retrieved the list via getBookIds() must perform external synchronization before accessing the list. Your question also doesn't show how you are actually using the SynchronizedBookIdsAggregator class, which leaves us with not enough information to fully answer your question.
Below would be a safer version of the class:
public class SynchronizedBookIdsAggregator {
private List<String> bookIds;
public SynchronizedBookIdsAggregator() {
bookIds = new ArrayList<String>();
}
public void updateBookIds(List<String> ids){
synchronized (this) {
bookIds.addAll(ids);
}
}
public List<String> getBookIds() {
// synchronized here for memory visibility of the bookIds field
synchronized(this) {
return bookIds;
}
}
public void setBookIds(List<String> bookIds) {
// synchronized here for memory visibility of the bookIds field
synchronized(this) {
this.bookIds = bookIds;
}
}
}
As alluded to earlier, the above code still has a potential problem with some thread accessing the ArrayList after it has been retrieved by getBookIds(). Since the ArrayList itself is not synchronized, accessing it after retrieving it should be synchronized on the chosen guard object:
public class SomeOtherClass {
public void run() {
SynchronizedBookIdsAggregator aggregator = getAggregator();
List<String> bookIds = aggregator.getBookIds();
// Access to the bookIds list must happen while synchronized on the
// chosen guard object -- in this case, aggregator
synchronized(aggregator) {
<work with the bookIds list>
}
}
}
I can imagine using Collections.newSynchronizedList as part of the design of this aggregator, but it is not a panacea. Concurrency design really requires an understanding of the underlying concerns, more than "picking the right tool / collection for the job" (although the latter is not unimportant).
Another potential option to look at is CopyOnWriteArrayList.
As skaffman alluded to, it might be better to not allow direct access to the bookIds list at all (e.g., remove the getter and setter). If you enforce that all access to the list must run through methods written in SynchronizedBookIdsAggregator, then SynchronizedBookIdsAggregator can enforce all concurrency control of the list. As my answer above indicates, allowing consumers of the aggregator to use a "getter" to get the list creates a problem for the user of that list: to write correct code they must have knowledge of the synchronization strategy / guard object, and furthermore they must also use that knowledge to actively synchronize externally and correctly.
Regarding your second approach. What you have shown looks technically correct (good!).
But, presumably you are going to read from masterBookIds at some point, too? And you don't show or describe that part of the program! So when you start thinking about when and how you are going to read masterBookIds (i.e. the return value of fetchMasterListOfBookIds()), just remember to consider concurrency concerns there too! :)
If you make sure all tasks/worker threads have finished before you start reading masterBookIds, you shouldn't have to do anything special.
But, at least in the code you have shown, you aren't ensuring that.
Note that libraryBookIdsExecutor.shutdown() returns immediately. So if you start using the masterBookIds list immediately after fetchMasterListOfBookIds() returns, you will be reading masterBookIds while your worker threads are actively writing data to it, and this entails some extra considerations.
Maybe this is what you want -- maybe you want to read the collection while it is being written to, to show realtime results or something. But then you must consider synchronizing properly on the collection if you want to iterate over it while it is being written to.
If you would just like to make sure all writes to masterBookIds by worker threads have completed before fetchMasterListOfBookIds() returns, you could use ExecutorService.awaitTermination (in combination with .shutdown(), which you are already calling).
Collections.SynchronizedList (which is the wrapper type you'd get) would synchronize almost every method on either itself or a mutex object you pass to the constructor (or Collections.synchronizedList(...) ). Thus it would basically be the same as your approach.
All the methods called using the wrapper returned by Collections.synchronizedList() will be synchronized. This means that the addAll method of normal List when called by this wrapper will be something like this :-
synchronized public static <T> boolean addAll(Collection<? super T> c, T... elements)
So, every method call for the list (using the reference returned and not the original reference) will be synchronized.
However, there is no synchronization between different method calls.
Consider following code snippet :-
List<String> l = Collections.synchronizedList(new ArrayList<String>);
l.add("Hello");
l.add("World");
While multiple threads are accessing the same code, it is quite possible that after Thread A has added "Hello", Thread B will start and again add "Hello" and "World" both to list and then Thread A resumes. So, list would have ["hello", "hello", "world", "world"] instead of ["hello", "world", hello", "world"] as was expected. This is just an example to show that list is not thread-safe between different method calls of the list. If we want the above code to have desired result, then it should be inside synchronized block with lock on list (or this).
However, with your design there is only one method call. SO IT IS SAME AS USING Collections.synchronizedList().
Moreover, as Mike Clark rightly pointed out, you should also synchronized getBookIds() and setBookIds(). And synchronizing it over List itself would be more clear since it is like locking the list before operating on it and unlocking it after operating. So that nothing in-between can use the List.

Categories

Resources