Does synchronized block cause all write cache to flush? - java

I am interested in how synchronized works in sense how/when it flushes writes from local caches. Lets imagine I have following code:
class Scratch1 {
int counter = 0;
Scratch1() throws ExecutionException, InterruptedException {
counter += 5;
counter += 5;
// Does this cause to flush possibly cached value written by main thread even if it locks
// on totally unrelated object and the write doesnt happen inside the sync block?
synchronized (String.class) {}
Executors.newCachedThreadPool().submit(() -> {
for (int i = 0; i < 1000; i++) {
counter += 5;
}
synchronized (Integer.class) {}
}).get();
System.out.println(counter);
}
}
class Scratch2 {
int counter = 0;
Scratch2() throws ExecutionException, InterruptedException {
// Or is this only possible working way how flush written data.
synchronized (String.class) {
counter += 5;
counter += 5;
}
Executors.newCachedThreadPool().submit(() -> {
synchronized (Integer.class) {
for (int i = 0; i < 1000; i++) {
counter += 5;
}
}
}).get();
System.out.println(counter);
}
}
class Scratch3 {
volatile int counter = 0;
Scratch3() throws ExecutionException, InterruptedException {
counter += 5;
counter += 5;
Executors.newCachedThreadPool().submit(() -> {
for (int i = 0; i < 1000; i++) {
counter += 5;
}
}).get();
System.out.println(counter);
}
}
I have several questions:
Does all three examples share same "thread-safety" level (taking into account specifics like first write is done by one thread and second write is done after first one (is it?) and by another thread) i.e. "is it guaranteed that 5010 is printed"?
Is there performance difference (at least theoretical) in "operating" outside a synchronized block or working with non-volatile properties (I would expect volatile access to be slower as this post confirms) but in case of synchronized block is the "flushing" price paid only when crossing synchronized start/end or is there also difference while inside the block?

I am interested in how synchronized works in sense how/when it flushes writes from local caches.
Actually, synchronized doesn't flush writes from local caches. It just acts as if it did so.
Does all three examples share same "thread-safety" level (taking into account specifics like first write is done by one thread and second write is done after first one (is it?) and by another thread) i.e. "is it guaranteed that 10 is printed"?
They all provide slightly different forms of thread safety. None of them are really safe if other threads are accessing the object at the same time. For example, another thread accessing counter would have to hold both the String.class and the Integer.class locks to ensure ensure it didn't see counter during an operation. The third one uses increment operations that aren't atomic, though it's safe if no other thread tries to modify counter.
Is there performance difference (at least theoretical) in "operating" outside a synchronized block or working with non-volatile properties (I would expect volatile access to be slower as this post confirms) but in case of synchronized block is the "flushing" price paid only when crossing synchronized start/end or is there also difference while inside the block?
No difference. Entering a synchronized block has a cost because the lock has to be acquired and some optimizations have to disabled across the entry point. Exiting the block has similar costs.
Inside the block, there are no costs because the safety is provided by the programmer ensuring they don't allow any thread to modify the object unless it holds the same lock and no two threads can hold the same lock at the same time. Generally speaking, code may not even know whether or not it's inside one or more synchronized blocks because it can be deep down the call tree.

Related

Java Selling Tickets with Multithreading

I have two threads to sell tickets.
public class MyThread {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread thread1 = new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sell();
} }, "A");
thread1.start();
Thread thread2 = new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sell();
} }, "B");
thread2.start();
}
}
class Ticket {
private Integer num = 20 ;
private Object obj = new Object();
public void sell() {
// why shouldn't I use "num" as a monitor object ?
// I thought "num" is unique among two threads.
synchronized ( num ) {
if (this.num >= 0) {
System.out.println(Thread.currentThread().getName() + " sells " + this.num + "th ticket");
this.num--;
}
}
}
}
The output will be wrong if I use num as a monitor object.
But if I use obj as a monitor object, the output will be correct.
What's the difference between using num and using obj ?
===============================================
And why does it still not work if I use (Object)num as a monitor object ?
class Ticket {
private int num = 20 ;
private Object obj = new Object();
public void sell() {
// Can I use (Object)num as a monitor object ?
synchronized ( (Object)num ) {
if (this.num >= 0) {
System.out.println(Thread.currentThread().getName() + " sells " + this.num + "th ticket");
this.num--;
}
}
}
}
Integer is a boxed value. It contains a primitive int, and the compiler deals with autoboxing/autounboxing that int. Because of this, the statement this.num-- is actually:
num=Integer.valueOf(num.intValue()-1)
That is, the num instance containing the lock is lost once you perform that update.
The fundamental problem here is synchronizing on a non-final value.
The most important thing to understand about the Java Memory Model - that is, what values a thread sees whilst executing a Java program - is the happens-before relationship.
In the specific case of a synchronized block, actions done in one thread before exiting the synchronized block happen before actions done inside the synchronized block in another thread - so, if the first thread increments a variable inside that synchronized block, the second thread sees that updated value.
This goes over and above the well-known fact that a synchronized block can only be entered by one thread at a time: only one thread at a time and you get to see what the previous thread did.
// Thread 1 // Thread 2
synchronized (monitor) {
num = 1
} // Exiting monitor
// *happens before*
// entering monitor
synchronized (monitor) {
int n = num; // Guaranteed to see n = 1 (provided no other thread has entered a block synchronized on monitor and changed it first).
}
There is a very important caveat to this guarantee: it only holds if the two executions of the synchronized block use the same monitor. And that's not the same variable, it's the same actual concrete object on the heap (variables don't have monitors, they're just pointers to a value in the heap).
So, if you reassign the monitor inside the synchronized block:
synchronized (num) {
if (num > 0) {
num--; // This is the same as `num = Integer.valueOf(num.intValue() - 1);`
}
}
then you are destroying the happens-before guarantee, because the next thread to arrive at that synchronized block is entering the monitor of a different object (*).
Once you do, the behavior of your program is ill-defined: if you're lucky, it fails in an obvious way; if you're very unlucky, it can seem to work, and then start failing mysteriously at a later date.
Your code is just broken.
This isn't something that's specific to Integers either: this code would have the same problem.
// Assume `Object someObject = new Object();` is defined as a field.
synchronized (someObject) {
someObject = new Object();
}
(*) Actually, you still get a happens-before relationship for the new object: it's just not for the things inside this synchronized block, it's for things that happened in some other synchronized block that used the object as the monitor. Essentially, it's impossible to reason about what this means, so you may as well just consider it "broken".
The correct way to do it is to synchronize on a field that you can't (not just don't) reassign. You could simply synchronize on this (which can't be reassigned):
synchronized (this) {
if (num > 0) {
num--; // This is the same as `num = Integer.valueOf(num.intValue() - 1);`
}
}
Now it doesn't matter that you're reassigning num inside the block, because you're not synchronizing on it any more. You get the happens-before guarantee from the fact that you're always synchronizing on the same thing.
Note, however, that you must always access num from inside a synchronized block - for example, if you have a getter to get the number of tickets remaining, that must also synchronize on this, in order to get the happens-before guarantee that the value changed in the sell() method is visible in that getter.
This works, but it may not be entirely desirable: anybody who has access to a reference to your Ticket instance can also synchronize on it. This means they can potentially deadlock your code.
Instead, it is a common practice to introduce a private field which is used purely for locking: this is what the obj field gives you. The only modification from your code should be to make it final (and give it a better name than obj):
private final Object obj = new Object();
This can't be accessed outside your class, so nefarious clients cannot cause a deadlock for you directly.
Again, this can't be reassigned inside your synchronized block (or anywhere else), so there is no risk of you breaking the happens-before guarantee by reassigning it.

Why does wait(100) cause synchronized method to fail in multi threaded?

I am referencing from Baeldung.com. Unfortunately, the article does not explain why this is not a thread safe code. Article
My goal is to understand how to create a thread safe method with the synchronized keyword.
My actual result is: The count value is 1.
package NotSoThreadSafe;
public class CounterNotSoThreadSafe {
private int count = 0;
public int getCount() { return count; }
// synchronized specifies that the method can only be accessed by 1 thread at a time.
public synchronized void increment() throws InterruptedException { int temp = count; wait(100); count = temp + 1; }
}
My expected result is: The count value should be 10 because of:
I created 10 threads in a pool.
I executed Counter.increment() 10 times.
I make sure I only test after the CountDownLatch reached 0.
Therefore, it should be 10. However, if you release the lock of synchronized using Object.wait(100), the method become not thread safe.
package NotSoThreadSafe;
import org.junit.jupiter.api.Test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CounterNotSoThreadSafeTest {
#Test
void incrementConcurrency() throws InterruptedException {
int numberOfThreads = 10;
ExecutorService service = Executors.newFixedThreadPool(numberOfThreads);
CountDownLatch latch = new CountDownLatch(numberOfThreads);
CounterNotSoThreadSafe counter = new CounterNotSoThreadSafe();
for (int i = 0; i < numberOfThreads; i++) {
service.execute(() -> {
try { counter.increment(); } catch (InterruptedException e) { e.printStackTrace(); }
latch.countDown();
});
}
latch.await();
assertEquals(numberOfThreads, counter.getCount());
}
}
This code has both of the classical concurrency problems: a race condition (a semantic problem) and a data race (a memory model related problem).
Object.wait() releases the object's monitor and another thread can enter into the synchronized block/method while the current one is waiting. Obviously, author's intention was to make the method atomic, but Object.wait() breaks the atomicity. As result, if we call .increment() from, let's say, 10 threads simultaneously and each thread calls the method 100_000 times, we get count < 10 * 100_000 almost always, and this isn't what we'd like to. This is a race condition, a logical/semantic problem. We can rephrase the code... Since we release the monitor (this equals to the exit from the synchronized block), the code works as follows (like two separated synchronized parts):
public void increment() {
int temp = incrementPart1();
incrementPart2(temp);
}
private synchronized int incrementPart1() {
int temp = count;
return temp;
}
private synchronized void incrementPart2(int temp) {
count = temp + 1;
}
and, therefore, our increment increments the counter not atomically. Now, let's assume that 1st thread calls incrementPart1, then 2nd one calls incrementPart1, then 2nd one calls incrementPart2, and finally 1st one calls incrementPart2. We did 2 calls of the increment(), but the result is 1, not 2.
Another problem is a data race. There is the Java Memory Model (JMM) described in the Java Language Specification (JLS). JMM introduces a Happens-before (HB) order between actions like volatile memory write/read, Object monitor's operations etc. https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4.5 HB gives us guaranties that a value written by one thread will be visible by another one. Rules how to get these guaranties are also known as Safe Publication rules. The most common/useful ones are:
Publish the value/reference via a volatile field (https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4.5), or as the consequence of this rule, via the AtomicX classes
Publish the value/reference through a properly locked field (https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4.5)
Use the static initializer to do the initializing stores
(http://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.4)
Initialize the value/reference into a final field, which leads to the freeze action (https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.5).
So, to have the counter correctly (as JMM has defined) visible, we must make it volatile
private volatile int count = 0;
or do the read over the same object monitor's synchronization
public synchronized int getCount() { return count; }
I'd say that in practice, on Intel processors, you read the correct value without any of these additional efforts, with just simple plain read, because of TSO (Total Store Ordering) implemented. But on a more relaxed architecture, like ARM, you get the problem. Follow JMM formally to be sure your code is really thread-safe and doesn't contain any data races.
Why int temp = count; wait(100); count = temp + 1; is not thread-safe? One possible flow:
First thread reads count (0), save it in temp for later, and waits, allowing second thread to run (lock released);
second thread reads count (also 0), saved in temp, and waits, eventually allowing first thread to continue;
first thread increments value from temp and saves in count (1);
but second thread still holds the old value of count (0) in temp - eventually it will run and store temp+1 (1) into count, not incrementing its new value.
very simplified, just considering 2 threads
In short: wait() releases the lock allowing other (synchronized) method to run.

Are unsynchronized reads (combined with synchronized writes) eventually consistent

I have a use case with many writer threads and a single reader thread. The data being written is an event counter which is being read by a display thread.
The counter only ever increases and the display is intended for humans, so the exact point-in-time value is not critical. For this purpose, I would consider a solution to be correct as long as:
The value seen by the reader thread never decreases.
Reads are eventually consistent. After a certain amount of time without any writes, all reads will return the exact value.
Assuming writers are properly synchronized with each other, is it necessary to synchronize the reader thread with the writers in order to guarantee correctness, as defined above?
A simplified example. Would this be correct, as defined above?
public class Eventual {
private static class Counter {
private int count = 0;
private Lock writeLock = new ReentrantLock();
// Unsynchronized reads
public int getCount() {
return count;
}
// Synchronized writes
public void increment() {
writeLock.lock();
try {
count++;
} finally {
writeLock.unlock();
}
}
}
public static void main(String[] args) {
List<Thread> contentiousThreads = new ArrayList<>();
final Counter sharedCounter = new Counter();
// 5 synchronized writer threads
for(int i = 0; i < 5; ++i) {
contentiousThreads.add(new Thread(new Runnable(){
#Override
public void run() {
for(int i = 0; i < 20_000; ++i) {
sharedCounter.increment();
safeSleep(1);
}
}
}));
}
// 1 unsynchronized reader thread
contentiousThreads.add(new Thread(new Runnable(){
#Override
public void run() {
for(int i = 0; i < 30; ++i) {
// This value should:
// +Never decrease
// +Reach 100,000 if we are eventually consistent.
System.out.println("Count: " + sharedCounter.getCount());
safeSleep(1000);
}
}
}));
contentiousThreads.stream().forEach(t -> t.start());
// Just cleaning up...
// For the question, assume readers/writers run indefinitely
try {
for(Thread t : contentiousThreads) {
t.join();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void safeSleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
//Don't care about error handling for now.
}
}
}
There is no guarantee that the readers would ever see an update to the count. A simple fix is to make count volatile.
As noted in another answer, in your current example, the "Final Count" will be correct because the main thread is joining the writer threads (thus establishing a happens-before relationship). however, your reader thread is never guaranteed to see any update to the count.
JTahlborn is correct, +1 from me. I was rushing and misread the question, I was assuming wrongly that the reader thread was the main thread.
The main thread can display the final count correctly due to the happens-before relationship:
All actions in a thread happen-before any other thread successfully returns from a join on that thread.
Once the main thread has joined to all the writers then the counter's updated value is visible. However, there is no happens-before relationship forcing the reader's view to get updated, you are at the mercy of the JVM implementation. There is no promise in the JLS about values getting visible if enough time passes, it is left open to the implementation. The counter value could get cached and the reader could possibly not see any updates whatsoever.
Testing this on one platform gives no assurance of what other platforms will do, so don't think this is OK just because the test passes on your PC. How many of us develop on the same platform we deploy to?
Using volatile on the counter or using AtomicInteger would be good fixes. Using AtomicInteger would allow removing the locks from the writer thread. Using volatile without locking would be OK only in a case where there is just one writer, when two or more writers are present then ++ or += not being threadsafe will be an issue. Using an Atomic class is a better choice.
(Btw eating the InterruptedException isn't "safe", it just makes the thread unresponsive to interruption, which happens when your program asks the thread to finish early.)

synchronize on multiple objects

In a previous question -> my question here i received a good solution (which works) to resolve my issue.
But i haven't understand how exactly works.
So if i have many threads that can enter concurrently on this synchronized block, and according to the java docs this code is:
synchronized(...){
//atomic for the operation inside
}
So, i' m asking:
why this operation is atomic:
for (int j = 0; j < column; j++) {
matrix[row][j] += 1;
}
and not this one:
System.out.println("begin print");
for (int i = 0; i < this.row; i++) {
System.out.println();
for (int j = 0; j < column; j++)
System.out.print(matrix[i][j]);
}
System.out.println();
System.out.println("end print");
my full function is this:
public void increaseRow(Integer row) {
synchronized (rows.get(row)) {
for (int j = 0; j < column; j++) {
matrix[row][j] += 1;
}
System.out.println("begin print");
for (int i = 0; i < this.row; i++) {
System.out.println();
for (int j = 0; j < column; j++)
System.out.print(matrix[i][j]);
}
System.out.println();
System.out.println("end print");
}
}
Could someone provide me a useful explanation, i'll appreciate a lot.
As it's stated in comment, System.out.println is not thread safe operation.
The problem is the way you lock your critical section.
synchronized (rows.get(row)) { }
This code means, that you are locking on specific row, not the whole table, so if you have N rows, that means N locks exist at the same time, and there fore N threads can run simultaneously populating System.out in parallel.
Locking on a row gives you a better parallelism: Thread working on row 2, can work at the same time, as Thread working on row 3.
Another option is to have a single lock for the whole table section.
Object lock = new Object();
...
public void someMethod(){
synchronized(lock){...}
}
In this case there is only one lock, and only one Thread executing it at the same time, so you are effectively calling your System.out synchronously from your code.
Locking on a table, decreases parallelism, since you decrease number of locks, available: Thread working on row 2, would need to wait for Thread working on row 3, to release the lock.
Thread safety, that synchronous guaranties affects only functions, written in the block, not externally called functions, it does not make System.out atomic operation.
why dont you use your class object: synchronized(this)
or, even more secure: synchronized(YourClassName.class)
or some other lock?
Object lock = new Object();
...
public void someMethod(){
synchronized(lock){...}
}
Every Java object created, including every Class loaded, has an associated lock or monitor. Putting code inside a synchronized block makes the compiler append instructions to acquire the lock on the specified object before executing the code, and release it afterwards (either because the code finishes normally or abnormally). Between acquiring the lock and releasing it, a thread is said to "own" the lock. At the point of Thread A wanting to acquire the lock, if Thread B already owns the it, then Thread A must wait for Thread B to release it.
(http://www.javamex.com/tutorials/synchronization_concurrency_synchronized1.shtml)
but if your lock changes, while a thread uses this lock in a synchronized block, it can occure that another block can enter the synchronized block with this changed lock.
Example:
Object lock = new Object();
int value = 0;
public void increment(){
synchronized(lock){value++;}
}
public void printValue(){
synchronized(lock){System.out.println(value);}
}
timeline:
thread1:
calling printValue() //taking the lock
thread2:
lock = new Object(); //the lock changes, its another object now
calling increment() //taking this new lock. the old lock is still reserved by thread1
value is getting incrementing.
threat1:
printing the wrong value.
EDIT: Didn't see that he needs a lock for each row.

Java threading synchronized block behavior - synchronized vs synchronized()? [duplicate]

This question already has answers here:
Is there an advantage to use a Synchronized Method instead of a Synchronized Block?
(23 answers)
Closed 9 years ago.
I have simple question but has problem to find answer on it.
Question is if synchronized method is equal to synchronized(this) - mean do same locking.
I want to write thread safe code with reduced thread locking (not want use always synchronized methods but sometime partial synchronization critical sections only).
Could you explain me if this code is equal or not and why in short words (examples is simplified to show atomic problem)?
Examples
Is this mixed locking code is equal to brute force code bellow:
public class SynchroMixed {
int counter = 0;
synchronized void writer() {
// some not locked code
int newCounter = counter + 1;
// critical section
synchronized(this) {
counter = newCounter;
}
}
synchronized int reader() {
return counter;
}
}
Brute force code (each method is locked including not critical section:
public class SynchroSame {
int counter = 0;
synchronized void writer() {
int newCounter = counter + 1;
counter = newCounter;
}
synchronized int reader() {
return counter;
}
}
Or I should write this code (this is for sure valid but more micro coding and unclear).
public class SynchroMicro {
int counter = 0;
void writer() {
// some not locked code
int newCounter = counter + 1;
// critical section
synchronized(this) {
counter = newCounter;
}
}
int reader() {
synchronized (this) {
return counter;
}
}
}
synchronized method and synchronized(this) means absolutely the same thing, and uses the same mutex behind. It's more question of taste what notation to prefer.
Personally I prefer synchronized(this), because it explicitly specifies the scope of the mutex lock which could be smaller than the whole method
All three examples are equivalent. Using synchronized on a method is the same as wrapping the entire body within synchronized(this) {}.
Then, by using synchronized(this) {} for some statements, the thread is only re-acquiring a lock it already owns: it's pointless here.
There is definitely no point in synchronized(this) within a synchronized method since entering the method is already implicitly synchronized(this).
That was just a syntax mistake on your part since you clearly intend to reduce the scope of the critical section, but the reduced scope introduces a data race into your code: you must both read and write the shared variable within the same synchronized block.
In addition, even if a method only reads the shared variable, it still must do that in a synchronized block; otherwise it may never observe any writes by other threads. This is the basic semantics of Java's Memory Model.
Now, if what you are showing is really representative of your full problem, then you shouldn't even be using synchronized, but a simple AtomicInteger, which will have the best concurrent performance.
Synchronized method and block are absolutely similar from functional point of view. They both do the same task i.e. to avoid concurrent access to particular method or block of code within a method.
synchronized() block is more flexible and handy when you have a long method and just need a part of it to be synchronized. You need not lock access to the entire method, as we know synchronization has some performance issues associated with it. Hence it is always recommended to synchronize only need part of the code and not the entire method (if not required).

Categories

Resources