Using the lock of synchronize block - java

if I have variable Integer[] arr = new Integer[5] and i use one of the cells as synchronize block lock - can I use it inside the block?
synchronize(arr[index])
{
arr[index]++;
}
If the answer is yes - so what exactly the lock means? what the program do to this lock while synchronization?
another question - does it lock only the cell or all of the array?
In other words - Does another Thread can use the arr[index+1] in the block in parallel?
Thanks!

1) .... can I use it inside the block?
Yes
2) If the answer is yes - so what exactly the lock means? what the program do to this lock while synchronization?
What it means is that some other thread that attempts to synchronize on the same object will be blocked until "this code" releases the lock on the object.
There are also memory coherency effects. If you synchronize (properly) one thread is guaranteed to see changes made by another one.
3) another question - does it lock only the cell or all of the array?
Neither. It locks on the object (the Integer instance) that the array cell refers to.
Also the lock applies only to other threads that attempt to synchronize on the same object. If another thread attempts to synchronize on a different object, or if it attempts to access the object without synchronizing, then it is not blocked.
4) In other words - Can another thread use the arr[index+1] in the block in parallel?
It depends on precisely what the other thread does. See above.
Aside: Your example is rather odd. An Integer object is immutable, so there seems little point in synchronizing on it. This may be just a contrived example, but if not, then you most likely have a problem in your application design. Unfortunately, the example offers us no clues to understand what you are really trying to do here.
But the simple lessons are:
you synchronize on objects, not array elements, or variables
synchronization only works if all threads synchronize when using a shared object.

It locks the object (Integer) that happens to be at position index in the array at the beginning of the synchronized block. Which is not very useful in the case of Integers, because the statement arr[index]++ will replace the object with another (unlocked) one.
UPDATE
It doesn't lock anything useful, neither the full array, not the cell at position index. Besides, Integer objects (that are immutable) can be kept in a cache to be reused as a result of valueOf(). You may also get a NullPointerException if the array is not initialized.
In summary: don't do that.

Related

Is it thread-safe to synchronize only on add to HashSet?

Imagine having a main thread which creates a HashSet and starts a lot of worker threads passing HashSet to them.
Just like in code below:
void main() {
final Set<String> set = new HashSet<>();
final ExecutorService threadExecutor =
Executors.newFixedThreadPool(10);
threadExecutor.submit(() -> doJob(set));
}
void doJob(final Set<String> pSet) {
// do some stuff
final String x = ... // doesn't matter how we received the value.
if (!pSet.contains(x)) {
synchronized (pSet) {
// double check to prevent multiple adds within different threads
if (!pSet.contains(x)) {
// do some exclusive work with x.
pSet.add(x);
}
}
}
// do some stuff
}
I'm wondering is it thread-safe to synchronize only on add method? Is there any possible issues if contains is not synchronized?
My intuition telling me this is fine, after leaving synchronized block changes made to set should be visible to all threads, but JMM could be counter-intuitive sometimes.
P.S. I don't think it's a duplicate of How to lock multiple resources in java multithreading
Even though answers to both could be similar, this question addresses more particular case.
I'm wondering is it thread-safe to synchronize only on the add method? Are there any possible issues if contains is not synchronized as well?
Short answers: No and Yes.
There are two ways of explaining this:
The intuitive explanation
Java synchronization (in its various forms) guards against a number of things, including:
Two threads updating shared state at the same time.
One thread trying to read state while another is updating it.
Threads seeing stale values because memory caches have not been written to main memory.
In your example, synchronizing on add is sufficient to ensure that two threads cannot update the HashSet simultaneously, and that both calls will be operating on the most recent HashSet state.
However, if contains is not synchronized as well, a contains call could happen simultaneously with an add call. This could lead to the contains call seeing an intermediate state of the HashSet, leading to an incorrect result, or worse. This can also happen if the calls are not simultaneous, due to changes not being flushed to main memory immediately and/or the reading thread not reading from main memory.
The Memory Model explanation
The JLS specifies the Java Memory Model which sets out the conditions that must be fulfilled by a multi-threaded application to guarantee that one thread sees the memory updates made by another. The model is expressed in mathematical language, and not easy to understand, but the gist is that visibility is guaranteed if and only if there is a chain of happens before relationships from the write to a subsequent read. If the write and read are in different threads, then synchronization between the threads is the primary source of these relationships. For example in
// thread one
synchronized (sharedLock) {
sharedVariable = 42;
}
// thread two
synchronized (sharedLock) {
other = sharedVariable;
}
Assuming that the thread one code is run before the thread two code, there is a happens before relationships between thread one releasing the lock and thread two acquiring it. With this and the "program order" relations, we can build a chain from the write of 42 to the assignment to other. This is sufficient to guarantee that other will be assigned 42 (or possibly a later value of the variable) and NOT any value in sharedVariable before 42 was written to it.
Without the synchronized block synchronizing on the same lock, the second thread could see a stale value of sharedVariable; i.e. some value written to it before 42 was assigned to it.
That code is thread safe for the the synchronized (pSet) { } part :
if (!pSet.contains(x)) {
synchronized (pSet) {
// Here you are sure to have the updated value of pSet
if (!pSet.contains(x)) {
// do some exclusive work with x.
pSet.add(x);
}
}
because inside the synchronized statement on the pSet object :
one and only one thread may be in this block.
and inside it, pSet has also its updated state guaranteed by the happens-before relationship with the synchronized keyword.
So whatever the value returned by the first if (!pSet.contains(x)) statement for a waiting thread, when this waited thread will wake up and enter in the synchronized statement, it will set the last updated value of pSet. So even if the same element was added by a previous thread, the second if (!pSet.contains(x)) would return false.
But this code is not thread safe for the first statement if (!pSet.contains(x)) that could be executed during a writing on the Set.
As a rule of thumb, a collection not designed to be thread safe should not be used to perform concurrently writing and reading operations because the internal state of the collection could be in a in-progress/inconsistent state for a reading operation that would occur meanwhile a writing operation.
While some no thread safe collection implementations accept such a usage in the facts, that is not guarantee at all that it will always be true.
So you should use a thread safe Set implementation to guarantee the whole thing thread safe.
For example with :
Set<String> pSet = ConcurrentHashMap.newKeySet();
That uses under the hood a ConcurrentHashMap, so no lock for reading and a minimal lock for writing (only on the entry to modify and not the whole structure).
No,
You don't know in what state the Hashset might be during add by another Thread. There might be fundamental changes ongoing, like splitting of buckets, so that contains may return false during the adding by another thread, even if the element would be there in a singlethreaded HashSet. In that case you would try to add an element a second time.
Even Worse Scenario: contains might get into an endless loop or throw an exception because of an temporary invalid state of the HashSet in the memory used by the two threads at the same time.

Synchronizing in a for each loop still throws ConcurrentModificationExceptions

I'm trying to iterate through a loop on one thread, like so:
for (UnitTask task : chain) {
g.drawLine((int) task.getLocation().getX(), (int) task.getLocation().getY(), (int) currentPos.getX(), (int) currentPos.getY());
g.fillOval((int) task.getLocation().getX() - 2, (int) task.getLocation().getY() - 2, 5, 5);
currentPos = task.getLocation();
}
However, I have another thread (the Swing event thread) which can add to this object. Hence, ConcurrentModificationException. I tried obtaining a lock by surrounding the code with synchronized (chain) { ... }, but I still get the errors.
As a bit of a Java synchronization newbie, I'm a little confused as to why. I would expect this to make the loop thread-safe, but evidently, it is not.
Interestingly, chain is an instance of a custom class, but it is only a thin wrapper around a LinkedList. The list itself is private, and there's no way for an external class to retrive it directly (there are methods to explicitly add/remove objects), so I wouldn't expect this to affect the outcome.
The meaning of
synchronized (c) {
... code that uses c ...
}
is
wait for c to be unlocked
lock c
execute the body
unlock c
So if you synchronize in your thread, then your thread will wait for c to be unlocked and then dive in.
Now, if you do not synchronize the code on the other thread that modifies c, that code is going to just go ahead and modify c without waiting for a lock. Synchronizing a block in one thread does not make another thread wait for a lock. If the other thread has a line such as
c.add(someOtherTask)
that is not in a synchronized block, then it's going to do the add no matter what. This is the cause of your exception. It is also the reason why you saw the exception even though you put the code in your thread in a synchronized block: your code was "playing by the rules" but the other thread couldn't have cared less.
Be careful about synchronizing long-running code though. You are better off, as Stephen C says, to use a concurrent collection type.
Synchronization will not necessarily help.
Basically the problem is that you are using a collection type that does not allow the collection to be modified while an iteration is in progress (except via the iterator's remove method ... if supported). This is not a threading / synchronization issue per se. (And if you try to solve it simply by synchronization, you may introduce another problem.)
If you want to be able to iterate and modify at the same time, you will need to use a different collection type such as ConcurrentLinkedDeque instead of LinkedList.
If the iteration and writing are happening on separate threads, then shouldn't synchronizing block the writing until the iteration is finished? Or am I missing something?
The problem will be in how you have implemented the synchronization:
If you are not explicitly doing some kind synchronization in your LinkedList version, then no synchronization is done for you.
If you use a synchronization wrapper created by one of the Collections.synchronizedXxx methods, then the javadocs for those methods clearly state that an Iterator object returned by the wrapper's iterator() method IS NOT synchronized.
If you are doing the synchronization by hand, then you have to make sure that everything is synchronizing on the same mutex. And that lock has to be held on that mutex for the duration of the iteration ... not just for the call the iterator().
And note that if you hold a lock for a long time (e.g. while you are iterating a long list), this can potentially block other threads that need to update the list for a long time. That kind of thing can be a concurrency bottleneck that can (in the worst case) reduce your system's performance to the speed of a single processor.
The ConcurrentXxx classes typically avoid this by relaxing the consistency guarantees for the sequences produced by the iterators. For instance, you may not see elements that were added to the collection after you started the iteration.

Synchronizing elements in an array

I am new to multi-threading in Java and don't quite understand what's going on.
From online tutorials and lecture notes, I know that the synchronized block, which must be applied to a non-null object, ensures that only one thread can execute that block of code. Since an array is an object in Java, synchronize can be applied to it. Further, if the array stores objects, I should be able to synchronize each element of the array too.
My program has several threads updated an array of numbers, hence I created an array of Long objects:
synchronized (grid[arrayIndex]){
grid[arrayIndex] += a.getNumber();
}
This code sits inside the run() method of the thread class which I have extended. The array, grid, is shared by all of my threads. However, this does not return the correct results while running the same program on one thread does.
This will not work. It is important to realize that grid[arrayIndex] += ... is actually replacing the element in the grid with a new object. This means that you are synchronizing on an object in the array and then immediately replacing the object with another in the array. This will cause other threads to lock on a different object so they won't block. You must lock on a constant object.
You can instead lock on the entire array object, if it is never replaced with another array object:
synchronized (grid) {
// this changes the object to another Long so can't be used to lock
grid[arrayIndex] += a.getNumber();
}
This is one of the reasons why it is a good pattern to lock on a final object. See this answer with more details:
Why is it not a good practice to synchronize on Boolean?
Another option would be to use an array of AtomicLong objects, and use their addAndGet() or getAndAdd() method. You wouldn't need synchronization to increment your objects, and multiple objects could be incremented concurrently.
The java class Long is immutable, you cannot change its value. So when you perform an action:
grid[arrayIndex] += a.getNumber();
it is not changing the value of grid[arrayIndex], which you are locking on, but is actually creating a new Long object and setting its value to the old value plus a.getNumber. So you will end up with different threads synchronizing on different objects, which leads to the results you are seeing
The synchronized block you have here is no good. When you synchronize on the array element, which is presumably a number, you're synchronizing only on that object. When you reassign the element of the array to a different object than the one you started with, the synchronization is no longer on the correct object and other threads will be able to access that index.
One of these two options would be more correct:
private final int[] grid = new int[10];
synchronized (grid) {
grid[arrayIndex] += a.getNumber();
}
If grid can't be final:
private final Object MUTEX = new Object();
synchronized (MUTEX) {
grid[arrayIndex] += a.getNumber();
}
If you use the second option and grid is not final, any assignment to grid should also be synchronized.
synchronized (MUTEX) {
grid = new int[20];
}
Always synchronize on something final, always synchronize on both access and modification, and once you have that down, you can start looking into other locking mechanisms, such as Lock, ReadWriteLock, and Semaphore. These can provide more complex locking mechanisms than synchronization that is better for scenarios where Java's default synchronization alone isn't enough, such as locking data in a high-throughput system (read/write locking) or locking in resource pools (counting semaphores).

Locking on a mutable object - Why is it considered a bad practice?

See this answer. It says:
Six really bad examples;
...
locking on a mutable field. e.g. synchronized(object) { object = ...; }
What's wrong with locking on a mutable field? What if object was declared as final but was not an immutable class?
It is a bad idea because if another thread changes the reference in the critical section, the threads will no longer see the same reference, and so they will not synchronize on the same object, thus running uncontrolled. Example:
synchronized(lock1) {
lock1 = new Object();
sharedVariable++;
}
Assume 2 threads are trying to enter this critical section. Thread 1 enters and thread 2 waits. Thread 1 goes in, reassigns lock1 and proceeds. Now thread 2 sees a different lock than what thread 1 acquired, which is also free, so it can also enter the critical section. Fun ensues!
If the object is final, you cannot reassign the reference to a different object, so the above problem no longer applies.
"Mutable" isn't the right word here. It's okay to lock on a mutable object, i.e. an object with state. What's wrong is to lock on a field, change it, and expect another thread to lock on the same object.
I don't think locking a mutable object is bad in itself. It is just very hard to get it right. There are other models for concurrent processing, like actors. I suggest you look into Akka, which can be used from both Java and Scala, and is a very solid implementation.

Is Java ArrayList / String / atomic variable reading thread safe?

I've been mulling this over & reading but can find an absolute authoritative answer.
I have several deep data structures made up of objects containing ArrayLists, Strings & primitive values. I can guarantee that the data in these structures will not change (no thread will ever make structural changes to lists, change references, change primitives).
I'm wondering if reading data in these structures is thread safe; i.e. is it safe to recursively read variables from the objects, iterate the ArrayLists etc. to extract information from the structures in multiple threads without synchronization?
The only reason why it wouldn't be safe is if one thread were writing to a field while another thread was simultaneously reading from it. No race condition exists if the data is not changing. Making objects immutable is one way of guaranteeing that they are thread safe. Start by reading this article from IBM.
The members of an ArrayList aren't protected by any memory barriers, so there is no guarantee that changes to them are visible between threads. This applies even when the only "change" that is ever made to the list is its construction.
Any data that is shared between thread needs a "memory barrier" to ensure its visibility. There are several ways to accomplish this.
First, any member that is declared final and initialized in a constructor is visible to any thread after the constructor completes.
Changes to any member that is declared volatile are visible to all threads. In effect, the write is "flushed" from any cache to main memory, where it can be seen by any thread that accesses main memory.
Now it gets a bit trickier. Any writes made by a thread before that thread writes to a volatile variable are also flushed. Likewise, when a thread reads a volatile variable, its cache is cleared, and subsequent reads may repopulate it from main memory.
Finally, a synchronized block is like a volatile read and write, with the added quality of atomicity. When the monitor is acquired, the thread's read cache is cleared. When the monitor is released, all writes are flushed to main memory.
One way to make this work is to have the thread that is populating your shared data structure assign the result to a volatile variable (or an AtomicReference, or other suitable java.util.concurrent object). When other threads access that variable, not only are they guaranteed to get the most recent value for that variable, but also any changes made to the data structure by the thread before it assigned the value to the variable.
If the data is never modified after it's created, then you should be fine and reads will be thread safe.
To be on the safe side, you could make all of the data members "final" and make all of the accessing functions reentrant where possible; this ensures thread safety and can help keep your code thread safe if you change it in the future.
In general, making as many members "final" as possible helps reduce the introduction of bugs, so many people advocate this as a Java best practice.
Just as an addendum to everyone else's answers: if you're sure you need to synchronize your array lists, you can call Collections.synchronizedList(myList) which will return you a thread safe implementation.
I cannot see how reading from ArrayLists, Strings and primitive values using multiple threads should be any problem.
As long as you are only reading, no synchronization should be necessary. For Strings and primitives it is certainly safe as they are immutable. For ArrayLists it should be safe, but I do not have it on authority.
Do NOT use java.util.Vector, use java.util.Collections.unmodifiableXXX() wrapper if they truly are unmodifiable, this will guarantee they won't change, and will enforce that contract. If they are going to be modified, then use java.util.Collections.syncronizedXXX(). But that only guarantees internal thread safety. Making the variables final will also help the compiler/JIT with optimizations.

Categories