Imagine the following program.
class Main {
static class Whatever {
int x = 0;
}
public static void main(String[] args) {
Whatever whatever = new Whatever();
Thread t = new Thread(() -> {
whatever.x = 1;
});
t.start();
try {
t.join();
}
catch (InterruptedException e) {
}
System.out.println(whatever.x);
}
}
The main-thread has cached whatever and x is set to 0. The other thread starts, caches whatever and sets the cached x to 1.
The output is
1
so the main-thread has seen the write. Why is that?
Why was the write done to the shared cache and why has the main-thread invalidated its cache to read from the shared cache? Why don't I need volatile here?
Because of the main thread joining on it. See
17.4.5 in the JLS:
All actions in a thread happen-before any other thread successfully returns from a join() on that thread.
Btw it is true that not having a happens-before doesn’t necessarily mean something won’t be visible.
Related
I am having writer and reader threads though I use AtomicBoolean and AtomicInteger I could see duplicate values in the reader thread, please help me to find what's wrong with my code.
package automic;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class AutomicTest {
public volatile AtomicBoolean isStopped = new AtomicBoolean(false);
public AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
AutomicTest test = new AutomicTest();
Thread writerThread = new Thread(() ->{
while(!test.isStopped.get()) {
test.count.incrementAndGet();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread readerThread = new Thread(() ->{
while(!test.isStopped.get()) {
System.out.println("Counter :"+test.count.get());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
writerThread.start();
readerThread.start();
Thread.sleep(4000);
test.isStopped.getAndSet(true);
writerThread.join();
readerThread.join();
}
}
Counter :1
Counter :2
Counter :3 // duplicate
Counter :3 // duplicate
Counter :4
Counter :5
Counter :7
Counter :8
Counter :9
Counter :10
Counter :11
Counter :12 // duplicate
Counter :12 // duplicate
Counter :13
Counter :15 // duplicate
Counter :15 // duplicate
Counter :17
Counter :18
Counter :19
Counter :20
Counter :21
Counter :22
Counter :23
Counter :24
Counter :25
Counter :26
Counter :27
Counter :28
Counter :29
Counter :30
Counter :31
Counter :32
Counter :33
Counter :34
Counter :35
Counter :36
Counter :37
Counter :38
Counter :39
Counter :40
The two big take-aways from this are that:
Thread.sleep(100) does not mean "Sleep for 100 ms, exactly to the nanosecond". It's a little less exact, depends on the granularity and accuracy of the internal OS clock, on native thread scheduling, other tasks running on the computer. Even the sleep-wakeup cycle takes some (a surprisingly high) amount of time.
Atomics are good when multiple threads cooperate independently. If you need them to be somehow dependent, and/or react to other threads' actions, atomics are not what you want. You'll need to use an actual synchronization mechanism.
Therefore, you cannot use sleep() and atomics to schedule two threads to run in a perfectly balanced tick-tock cycle.
This happens in your code:
Writer thread writes value 1 at time 100, then goes to sleep.
Reader thread reads value 1 at time 100, then goes to sleep. They can both easily run on the same ms, on a multicore system they can even run at exactly the same time, and they probably do.
Reader wakes up at time 200.0 and reads value 1 again.
Writer wakes up at time 200.02 and writes value 2. Oops, we just got a duplicate.
Do note that the threads can even flip back, in that case you'll see a missing number in the sequence, and occasionally you do. To balance the threads to run in a perfect A-B-A-B scheme you can do e.g. something like this:
public class AutomicTest {
private volatile boolean isStopped = false;
private final CyclicBarrier barrier = new CyclicBarrier(2);
private int count = 0;
public static void main(String[] args) throws InterruptedException {
AutomicTest test = new AutomicTest();
Thread writerThread = new Thread(() -> {
while (!test.isStopped) {
test.count++;
try {
test.barrier.await();
Thread.sleep(100);
} catch (InterruptedException | BrokenBarrierException ignored) {
Thread.currentThread().interrupt();
break;
}
}
});
Thread readerThread = new Thread(() -> {
while (!test.isStopped) {
try {
test.barrier.await();
System.out.println("Counter: " + test.count);
Thread.sleep(100);
} catch (InterruptedException | BrokenBarrierException ignored) {
Thread.currentThread().interrupt();
break;
}
}
});
writerThread.start();
readerThread.start();
Thread.sleep(4000);
test.isStopped = true;
writerThread.join();
readerThread.join();
}
}
The key here is a CyclicBarrier which is:
A synchronization aid that allows a set of threads to all wait for
each other to reach a common barrier point. CyclicBarriers are useful
in programs involving a fixed sized party of threads that must
occasionally wait for each other. The barrier is called cyclic
because it can be re-used after the waiting threads are released.
In this case the barrier is set up to have two synchronized parties - the Writer and the Reader:
The Writer first writes its value, then waits for all parties to arrive to the barrier (in other words, it waits for the Reader to read the value).
The Reader first waits for all parties to arrive to the barrier (in other words, it waits for the Writer to write a new value), only then reads the value.
In this scheme, the count value's visibility is enforced by the CyclicBarrier, so you do not even need an AtomicInteger here. More specifically:
Actions in a thread prior to calling await() happen-before [...]
actions following a successful return from the corresponding await()
in other threads.
Oh, and the isStopped also does not need an AtomicBoolean, a volatile is enough. But it will work either way. Sorry, I understand this was supposed to be a task to practice atomics, but they're not a good tool if you need the threads to wait for each other.
Footnote: The mechanism above is still not exactly correct when you remove the sleep() calls. The reason for that is that once released, the Reader races with the Writer on the next loop iteration. To fix that, the Writer must wait for the previous Reader to finish and the Reader must wait for its Writer to finish. This can be achiever by using a second barrier or perhaps a Phaser which I intentionally did not use in the example above as it is more advanced and you need to learn CyclicBarriers and CountDownLatches before moving on to Phasers. Also the shutdown mechanism needs to be tuned. Good luck!
EDIT: I actually wrote the no-sleep() double-Phaser solution and found out that it is much easier to read (if you do not care about long-running-task interruption which you normally should!) and much faster than an equivalent CyclicBarrier solution. So we both learned something today. Here it is:
public class AutomicTest {
private volatile boolean isStopped = false;
private final Phaser valueWritten = new Phaser(2);
private final Phaser valueRead = new Phaser(2);
private int count = 0;
public static void main(String[] args) throws InterruptedException {
AutomicTest test = new AutomicTest();
Thread writerThread = new Thread(() -> {
while (!test.isStopped) {
// wait for the previous value to be read
test.valueRead.arriveAndAwaitAdvance();
test.count++;
// acknowledge the write
test.valueWritten.arrive();
}
});
Thread readerThread = new Thread(() -> {
while (!test.isStopped) {
// wait for the value to be written
test.valueWritten.arriveAndAwaitAdvance();
System.out.println("Counter: " + test.count);
// acknowledge the read
test.valueRead.arrive();
}
});
writerThread.start();
readerThread.start();
test.valueRead.arrive(); // start the writer
Thread.sleep(4000);
test.isStopped = true;
test.valueRead.forceTermination();
test.valueWritten.forceTermination();
writerThread.join();
readerThread.join();
}
}
Because the done is non-volatile, so I will expect thread 1 will keep executing and printing out "Done".
But when I run the program, here is the output from console
Done
Undo
This means that thread 2's update is seen by thread 1, right? (But done isn't a volatile field.).
My explanation is that thread 1 and thread 2 are running in the same core. So that they can see update of the filed, please correct me if I'm wrong.
Overall, my question is why thread 1 can see the change of thread 2? Is this related to CPU cache write back/through to main memory? If it is, when does it happen?
public class Done {
boolean done = true;
public void m1() throws InterruptedException {
while (this.done) {
System.out.println("Done");
}
System.out.println("Undo");
}
public void undo() {
done = false;
}
public static void main(String[] args) {
ExecutorService es = Executors.newCachedThreadPool();
Done v = new Done();
es.submit(() -> {
try {
v.m1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}); // thread 1
es.submit(() -> {
v.undo();
}); // thread 2
es.shutdown();
}
}
The Java memory model's guarantees work in only one way. If something is guaranteed, like the visibility of a volatile write, then it'll work 100% of the time.
If there's no guarantee, it doesn't mean it'll never happen. Sometimes non-volatile writes will be seen by other threads. If you run this code many times on different machines with different JVMs, you'll probably see different results.
Look at this code:
public class VolatileTest {
private static boolean ready = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(){
#Override
public void run() {
ready = true;
System.out.println("t2 thread should stop!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t2 = new Thread(){
#Override
public void run() {
while(!ready){
System.out.println("invoking..");
}
System.out.println("I was finished");
}
};
t1.start();
t2.start();
}
}
I think the result of this code maybe:
t2 thread should stop!
invoking..
I was finished
because of in the multithreading, when the t1 modify 'ready' variable to true,then I made t1 sleep. At the moment, I think, to t2 the 'ready' variable is false!!! because t1 thread is not stop, the variable in t1 is invisible in t2.
But in fact.. I test many times. the result is always this:
Am my idea is wrong?
First of all, despite calling your class VolatileTest, you are not actually using volatile anywhere in your code.
Since the ready variable is not declared as volatile AND you are accessing it without any explicit synchronization, the behavior is not specified. Specifically, the JLS does not say whether the assignment made in thread 1 to the ready variable will be visible within thread 2.
Indeed, there is not even guaranteed that the run() method for thread 1 will be called before the run() method for thread 2.
Now it seems that your code (as written!) is behaving in a way that is consistent with the write of true always being visible immediately. However, there is no guarantee that that "always" is actually always, or that this will be the case on every Java platform.
I would not be surprised if the syscall associated with sleep is triggering memory cache flushing before the second thread is scheduled. That would be sufficient to cause consistent behavior. Moreover, there is likely to be serendipitous synchronization1 due to the println calls. However, these are not effects you should ever rely on.
1 - Somewhere in the output stream stack for System.out, the println call is likely to synchronize on the stream's shared data structures. Depending on the ordering of the events, this can have the effect of inserting a happens before relationship between the write and read events.
As I mentioned in my comment, there are no guarantees. ("There is no guarantee what value thread t2 will see for ready, because of improper synchronization in your code. It could be true, it could be false. In your case, t2 saw true. That is consistent with "there is no guarantee what value t2 will see")
You can easily get your test to fail by running it multiple times.
When I run below code that does your test 100 times, I always get 14-22 "notReadies", so 14-22% of the cases you will not see the change to ready in Thread t2.
public class NonVolatileTest {
private static boolean ready = false;
private static volatile int notReadies = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
ready = false;
// Copy original Thread 1 code from the OP here
Thread t2 = new Thread() {
#Override
public void run() {
if (!ready) {
notReadies++;
}
while (!ready) {
System.out.println("invoking..");
}
System.out.println("I was finished");
}
};
t1.start();
t2.start();
// To reduce total test run time, reduce the sleep in t1 to a
// more suitable value like "100" instead of "5000".
t1.join();
t2.join();
}
System.out.println("Notreadies: " + notReadies);
}
}
I was trying to implement something similar to Java's bounded BlockingQueue interface using Java synchronization "primitives" (synchronized, wait(), notify()) when I stumbled upon some behavior I don't understand.
I create a queue capable of storing 1 element, create two threads that wait to fetch a value from the queue, start them, then try to put two values into the queue in a synchronized block in the main thread. Most of the time it works, but sometimes the two threads waiting for a value start seemingly waking up each other and not letting the main thread enter the synchronized block.
Here's my (simplified) code:
import java.util.LinkedList;
import java.util.Queue;
public class LivelockDemo {
private static final int MANY_RUNS = 10000;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < MANY_RUNS; i++) { // to increase the probability
final MyBoundedBlockingQueue ctr = new MyBoundedBlockingQueue(1);
Thread t1 = createObserver(ctr, i + ":1");
Thread t2 = createObserver(ctr, i + ":2");
t1.start();
t2.start();
System.out.println(i + ":0 ready to enter synchronized block");
synchronized (ctr) {
System.out.println(i + ":0 entered synchronized block");
ctr.addWhenHasSpace("hello");
ctr.addWhenHasSpace("world");
}
t1.join();
t2.join();
System.out.println();
}
}
public static class MyBoundedBlockingQueue {
private Queue<Object> lst = new LinkedList<Object>();;
private int limit;
private MyBoundedBlockingQueue(int limit) {
this.limit = limit;
}
public synchronized void addWhenHasSpace(Object obj) throws InterruptedException {
boolean printed = false;
while (lst.size() >= limit) {
printed = __heartbeat(':', printed);
notify();
wait();
}
lst.offer(obj);
notify();
}
// waits until something has been set and then returns it
public synchronized Object getWhenNotEmpty() throws InterruptedException {
boolean printed = false;
while (lst.isEmpty()) {
printed = __heartbeat('.', printed); // show progress
notify();
wait();
}
Object result = lst.poll();
notify();
return result;
}
// just to show progress of waiting threads in a reasonable manner
private static boolean __heartbeat(char c, boolean printed) {
long now = System.currentTimeMillis();
if (now % 1000 == 0) {
System.out.print(c);
printed = true;
} else if (printed) {
System.out.println();
printed = false;
}
return printed;
}
}
private static Thread createObserver(final MyBoundedBlockingQueue ctr,
final String name) {
return new Thread(new Runnable() {
#Override
public void run() {
try {
System.out.println(name + ": saw " + ctr.getWhenNotEmpty());
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
}
}, name);
}
}
Here's what I see when it "blocks":
(skipped a lot)
85:0 ready to enter synchronized block
85:0 entered synchronized block
85:2: saw hello
85:1: saw world
86:0 ready to enter synchronized block
86:0 entered synchronized block
86:2: saw hello
86:1: saw world
87:0 ready to enter synchronized block
............................................
..........................................................................
..................................................................................
(goes "forever")
However, if I change the notify() calls inside the while(...) loops of addWhenHasSpace and getWhenNotEmpty methods to notifyAll(), it "always" passes.
My question is this: why does the behavior vary between notify() and notifyAll() methods in this case, and also why is the behavior of notify() the way it is?
I would expect both methods to behave in the same way in this case (two threads WAITING, one BLOCKED), because:
it seems to me that in this case notifyAll() would only wake up the other thread, same as notify();
it looks like the choice of the method which wakes up a thread affects how the thread that is woken up (and becomes RUNNABLE I guess) and the main thread (that has been BLOCKED) later compete for the lock — not something I would expect from the javadoc as well as searching the internet on the topic.
Or maybe I'm doing something wrong altogether?
Without looking too deeply into your code, I can see that you are using a single condition variable to implement a queue with one producer and more than one consumer. That's a recipe for trouble: If there's only one condition variable, then when a consumer calls notify(), there's no way of knowing whether it will wake the producer or wake the other consumer.
There are two ways out of that trap: The simplest is to always use notifyAll().
The other way is to stop using synchronized, wait(), and notify(), and instead use the facilities in java.util.concurrent.locks.
A single ReentrantLock object can give you two (or more) condition variables. Use one exclusively for the producer to notify the consumers, and use the other exclusively for the consumers to notify the producer.
Note: The names change when you switch to using ReentrantLocks: o.wait() becomes c.await(), and o.notify() becomes c.signal().
There appears to be some kind of fairness/barging going on using intrinsic locking - probably due to some optimization. I am guessing, that the native code checks to see if the current thread has notified the monitor it is about to wait on and allows it to win.
Replace the synchronized with ReentrantLock and it should work as you expect it. The different here is how the ReentrantLock handles waiters of a lock it has notified on.
Update:
Interesting find here. What you are seeing is a race between the main thread entering
synchronized (ctr) {
System.out.println(i + ":0 entered synchronized block");
ctr.addWhenHasSpace("hello");
ctr.addWhenHasSpace("world");
}
while the other two thread enter their respective synchronized regions. If the main thread does not get into its sync region before at least one of the two, you will experience this live-lock output you are describing.
What appears to be happening is that if both the two consumer threads hit the sync block first they will ping-pong with each other for notify and wait. It may be the case the JVM gives threads that are waiting priority to the monitor while threads are blocked.
package pkg_1;
public class ExpOnWaitMethod extends Thread {
static Double x = new Double(20);
public static void main(String[] args) {
ExpOnWaitMethod T1 = new ExpOnWaitMethod();
ExpOnWaitMethod T2 = new ExpOnWaitMethod();
T1.start();
T2.start();
}
public void run() {
Mag mag = new Mag();
synchronized (x) {
try {
for (int i = 1; i < 10; i++) {
mag.nop(Thread.currentThread());
x = i * 2.0;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Mag {
char ccc = 'A';
public void nop(Thread thr) throws InterruptedException {
System.out.print(ccc + " ");
ccc++;
if (thr.getState().toString().equalsIgnoreCase("runnable"))
Thread.currentThread().wait();
//thr.notify();
}
}
You need to hold the lock on the object you want to wait on (you can only call it within a synchronized block).
Also, calling wait on a Thread is very unusual and probably not what you want.
I am not sure what you are trying to do, but could you be confusing wait with sleep?
If you want to wait for another thread to finish, that would be anotherThread.join().
Before you call wait on an object, you must acquire that object's lock:
synchronized(obj)
{
obj.wait();
}
Your code is calling wait on a Thread object without acquiring the lock first.
I assume this is just a simplified test case to show your problem, but note that you probably want to be calling wait on an object that is accessible from all threads, not on the Thread objects themselves.
Someone should cite the API contract for java.lang.Object.wait(), which explains this directly. If a method raises an exception, read the documentation.
When in doubt, read the contract. (Bill McNeal on NewsRadio always kept his in his jacket pocket, a good metaphor for the JavaDoc API.. see "Crazy Prepared" under NewsRadio and ponder the imponderable.)