I am trying to learn volatile field modifier in multi-threading. I came across this statement:
Volatile is preferred in cases when one thread reads and writes a shared variable and other threads just read the same. Whereas if there are more than 2 threads performing read and write both on the shared variable then only volatile is not enough, you need to have synchronization as well.
I am aware that volatile provides visibility and happens-before guarantee, but is it possible to give a simple small example of code to demonstrate the above statements wherein a synchronized block is needed?
public class TwoInts {
private volatile int i1;
private volatile int i2;
public void set(int i1, int i2) {
this.i1 = i1;
this.i2 = i2;
}
public boolean same() {
return i1 == i2;
}
}
Now, if you have one thread doing this:
while (true) {
twoInts.set(i, i);
i++;
}
and a second thread doing this:
while (true) {
if (!twoInts.same()) {
System.out.println("Ooops!!");
}
}
then you will observe the problem that the quoted text is talking about. And if you rewrite the TwoInts class to make the methods synchronized then the "Oooops!!" messages will stop.
Let's say you have int i and two threads, you expect every one read i and set i = i + 1.
Like this:
public class Main {
private static volatile int i = 0;
public static void main(String[] args) throws Exception{
Runnable first = new Runnable() {
#Override
public void run() {
System.out.println("Thread_1 see i = " + i);
i++;
System.out.println("Thread_1 set i = " + i);
}
};
Runnable second = new Runnable() {
#Override
public void run() {
System.out.println("Thread_2 see i = " + i);
i++;
System.out.println("Thread_2 set i = " + i);
}
};
new Thread(first).start();
new Thread(second).start();
}
}
The result is:
Thread_1 see i = 0
Thread_2 see i = 0
Thread_1 set i = 1
Thread_2 set i = 2
As you see, Thread_2 get 0 and set 2(because Thread_1 has updated i to 1), which is not expected.
After adding syncronization,
public class Main {
private static volatile int i = 0;
public static void main(String[] args) throws Exception{
Runnable first = new Runnable() {
#Override
public void run() {
synchronized (Main.class) {
System.out.println("Thread_1 see i = " + i);
i++;
System.out.println("Thread_1 set i = " + i);
}
}
};
Runnable second = new Runnable() {
#Override
public void run() {
synchronized (Main.class) {
System.out.println("Thread_2 see i = " + i);
i++;
System.out.println("Thread_2 set i = " + i);
}
}
};
new Thread(first).start();
new Thread(second).start();
}
}
It works:
Thread_2 see i = 0
Thread_2 set i = 1
Thread_1 see i = 1
Thread_1 set i = 2
There are a lot of such examples... Here's one:
volatile int i = 0;
// Thread #1
while (true) {
i = i + 1;
}
// Thread #2
while (true) {
Console.WriteLine(i);
}
In this case, Thread #1 and Thread #2 are both reading the variable i, but only Thread #1 is writing to it. Thread #2 will always see an incrementing value of i.
Without the volatile keyword, you will occasionally see strange behavior, usually on multiprocessor machines or multicore CPUs. What happens (simplifying slightly here) is that Thread #1 and #2 are each running on their own CPU and each gets it's own copy of i (in it's CPU cache and/or registers). Without the volatile keyword, they may never update each other about the changed value.
Contrast with this example:
static volatile int i = 0;
// Thread #1
while (true) {
i = i + 1;
}
// Thread #2
while (true) {
if (i % 2 == 0)
i == 0;
else
Console.WriteLine(i);
}
So here, Thread #1 is trying to monotonically increment i, and Thread #2 is either going to set i to 0 (if i is even) or print it to the console if i is odd. You would expect that Thread #2 could never print an even number to the console, right?
It turns out that that is not the case. Because you have no synchronization around the access to i, it is possible that Thread #2 sees an odd value, moves to the else branch, and then Thread #1 increments the value of i, resulting in Thread #2 printing an even number.
In this scenario, one way of addressing the problem is to use basic locking as a form of synchronization. Because we cannot lock on a primitive, we introduce a blank Object to lock on:
static volatile int i = 0;
static Object lockOnMe = new Object();
// Thread #1
while (true) {
lock (lockOnMe) {
i = i + 1;
}
}
// Thread #2
while (true) {
lock (lockOnMe) {
if (i % 2 == 0)
i == 0;
else
Console.WriteLine(i);
}
}
Related
I work in the multithreading problem where 2 threads are started from the main. The code is provided below,
package com.multi;
public class App {
private int count = 0;
public void doWork() {
Thread thread1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10000; i++) {
count++;
}
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10000; i++) {
count++;
}
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Count is: " + count);
}
public static void main(String[] args) {
App worker = new App();
worker.doWork();
}
}
In the book, it informs that there is a possibility that the count value can be printed less than 20000 in some cases. They provided some explanation but even after reading for few times, I was unable to comprehend that completely. Like there is a try block that join the threads and that meant to ensure to complete both for loops.
a. In which circumstances, the count can be printed less than the 20000 and why both of the threads won't increase the count value?
b. If I wrote like
private volatile int count = 0;
private AtomicInteger count = 0;
will these essentially solve the issue?
Consider this sequence
count is 1
thread1 reads count 1 into local var x
thread2 reads count 1 into local var y
thread1 increments x to 2
thread1 writes x value 2 to count
thread2 increments y to 2
thread2 writes the y value 2 to count
When you do count++, it is a read from the field count, an addition of 1 to the value, and then a write of the result back to the field count, so my example sequence is essentially what can happen in your code.
In my example sequence, even though the field was incremented twice, the count is just 2, and not 3.
This happens because both threads are reading and writing from the same field at the same time.
Below is a trivial java program. It has a counter called "cnt" that is incremented and then added to a List called "monitor". "cnt" is incremented by multiple threads, and values are added to "monitor" by multiple threads.
At the end of the method "go()", cnt and monitor.size() should have the same value, but they don't. monitor.size() does have the correct value.
If you change the code by uncommenting one of the commented synchronized blocks, and commenting out the currently uncommented one, the code produces the expected results. Also, if you set the thread count (THREAD_COUNT) to 1, the code produces the expected results.
This can only be reproduced on a machine with multiple real cores.
public class ThreadTester {
private List<Integer> monitor = new ArrayList<Integer>();
private Integer cnt = 0;
private static final int NUM_EVENTS = 2313;
private final int THREAD_COUNT = 13;
public ThreadTester() {
}
public void go() {
Runnable r = new Runnable() {
#Override
public void run() {
for (int ii=0; ii<NUM_EVENTS; ++ii) {
synchronized( monitor) {
synchronized(cnt) { // <-- is this synchronized necessary?
monitor.add(cnt);
}
// synchronized(cnt) {
// cnt++; // <-- why does moving the synchronized block to here result in the correct value for cnt?
// }
}
synchronized(cnt) {
cnt++; // <-- why does moving the synchronized block here result in cnt being wrong?
}
}
// synchronized(cnt) {
// cnt += NUM_EVENTS; // <-- moving the synchronized block here results in the correct value for cnt, no surprise
// }
}
};
Thread[] threads = new Thread[THREAD_COUNT];
for (int ii=0; ii<THREAD_COUNT; ++ii) {
threads[ii] = new Thread(r);
}
for (int ii=0; ii<THREAD_COUNT; ++ii) {
threads[ii].start();
}
for (int ii=0; ii<THREAD_COUNT; ++ii) {
try { threads[ii].join(); } catch (InterruptedException e) { }
}
System.out.println("Both values should be: " + NUM_EVENTS*THREAD_COUNT);
synchronized (monitor) {
System.out.println("monitor.size() " + monitor.size());
}
synchronized (cnt) {
System.out.println("cnt " + cnt);
}
}
public static void main(String[] args) {
ThreadTester t = new ThreadTester();
t.go();
System.out.println("DONE");
}
}
Ok let's have a look at the different possibilities you mention:
1.
for (int ii=0; ii<NUM_EVENTS; ++ii) {
synchronized( monitor) {
synchronized(cnt) { // <-- is this synchronized necessary?
monitor.add(cnt);
}
synchronized(cnt) {
cnt++; // <-- why does moving the synchronized block to here result in the correct value for cnt?
}
}
First the monitor object is shared between the threads, therefore getting a lock on it (that is what synchronized does) will make sure that the code inside of the block will only be executed by one thread at a time. So the 2 synchronized inside of the outer one are not necessary, the code is protected anyway.
2.
for (int ii=0; ii<NUM_EVENTS; ++ii) {
synchronized( monitor) {
monitor.add(cnt);
}
synchronized(cnt) {
cnt++; // <-- why does moving the synchronized block here result in cnt being wrong?
}
}
Ok this one is a little bit tricky. cnt is an Integer object and Java does not allow modifying an Integer object (Integers are immutable) even though the code suggests that this is what is happening here. But what acutally will happen is that cnt++ will create a new Integer with the value cnt + 1 and override cnt.
This is what the code actually does:
synchronized(cnt) {
Integer tmp = new Integer(cnt + 1);
cnt = tmp;
}
The problem is that while one thread will create a new cnt object while all other threads are waiting to get a lock on the old one. The thread now releases the old cnt and will then try to get a lock on the new cnt object and get it while another thread gets a lock on the old cnt object. Suddenly 2 threads are in the critical section, executing the same code and causing a race condition. This is where the wrong results come from.
If you remove the first synchronized block (the one with monitor), then your result gets even more wrong because the chances of a race increase.
In general you should try to use synchronized only on final variables to prevent this from happening.
This is the code I am running:
public class MyRunnableClass implements Runnable {
static int x = 30;
int y = 0;
#Override
public void run() {
for(int i=0;i<30;i++){
getFromStash();
}
}
public synchronized void getFromStash(){
x--;
y++;
}
}
and my Test class:
public class MyRunnableClassTest {
public static void main(String[] args){
MyRunnableClass aa = new MyRunnableClass();
MyRunnableClass bb = new MyRunnableClass();
Thread a = new Thread(aa);
Thread b = new Thread(bb);
a.start();
b.start();
System.out.println(aa.y);
System.out.println(bb.y);
}
}
Sometimes I see output:
30
30
and sometimes I see:
30
0
Why? The method I have, is synchronized?
I actually expect to see something like 15 - 15 but it is definetly not what I am getting.
You need to wait for the threads to finish.
a.start();
b.start();
a.join();
b.join();
System.out.println(aa.y);
System.out.println(bb.y);
At that point you should see predictable results.
Added
Now you've had a chance to play - here's my attempt at what you seem to be trying to do.
public class MyRunnableClass implements Runnable {
static AtomicInteger stash = new AtomicInteger(1000);
int y = 0;
#Override
public void run() {
try {
while (getFromStash()) {
// Sleep a little 'cause I'm on a single-core machine.
Thread.sleep(0);
// Count how much of the stash I got.
y += 1;
}
} catch (InterruptedException ex) {
System.out.println("Interrupted!");
}
}
public boolean getFromStash() {
// It must be > 0
int was = stash.get();
while (was > 0) {
// Step down one.
if (stash.compareAndSet(was, was - 1)) {
// We stepped it down.
return true;
}
// Get again - we crossed with another thred.
was = stash.get();
}
// Must be 0.
return false;
}
}
Remove the bb and use only the aa object to create the two threads.
It's synchronized on this and you use two different objects (i.e. this values) - aa and bb. So practically you defeat the whole synchronization idea by using the two different objects.
Thread a = new Thread(aa);
Thread b = new Thread(aa);
a.start();
b.start();
Alternatively, you can do something like this.
public class MyRunnableClass implements Runnable {
private static final Object lock = new Object();
static int x = 30;
int y = 0;
#Override
public void run() {
for(int i=0;i<30;i++){
getFromStash();
}
}
public void getFromStash(){
synchronized(lock){
x--;
y++;
}
}
}
Here is what I think you want to achieve.
class Stash {
private int x = 30;
private int y = 0;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public synchronized void getFromStash(){
System.out.println("Method getFromStash called by " + Thread.currentThread().getName() + ".");
x--;
y++;
}
}
public class MyRunnableClass implements Runnable {
private Stash st = null;
private volatile boolean done = false;
public MyRunnableClass(Stash st){
this.st = st;
}
#Override
public void run() {
for(int i=0;i<30;i++){
this.st.getFromStash();
try {
double m = Math.random();
Thread.sleep((long)((m + 1) * 100.0));
}catch(InterruptedException ex){
ex.printStackTrace();
}
}
System.out.println("Thread ---> " + Thread.currentThread().getName() + " finished!");
this.done = true;
}
public static void main(String[] args) throws Exception {
Stash st = new Stash();
MyRunnableClass aa = new MyRunnableClass(st);
MyRunnableClass bb = new MyRunnableClass(st);
Thread a = new Thread(aa);
Thread b = new Thread(bb);
a.setName("Thread A");
b.setName("Thread B");
a.start();
b.start();
while (true){
System.out.println(st.getX() + " " + st.getY());
Thread.sleep(10);
if (aa.done && bb.done) break;
}
System.out.println("Main thread finished too!");
}
}
Since you print the values right after you start the threads, you're not going to "catch" the threads in the middle of the for loops. The thread scheduler is returning control to the main thread sometimes after the threads are done and sometimes before they start, but never during run(). You have to wait until the threads are done.
As you've already figured out, your first attempt didn't work the way you wanted because 1) you weren't waiting for the threads to finish, so sometimes you read the values before they'd done their work, and 2) you're not looking for each thread to pull from the stash 30 times, but rather for the sum total of the pulls to be 30 (divided among the threads however it happens).
Your move to stopping each thread when x > 0 instead of after N pulls is the right approach, but the test for whether x > 0 (and therefore whether to continue) needs to be synchronized as well. Otherwise you could test the value and find that x == 1, decide to do a pull, and then before you actually do it the other thread takes the last one. Then you do your pull, leaving x at -1 and the sum of the two y's at 31.
To solve this, you either need to put a check for x > 0 within the synchronized getFromStash() method (so you don't actually change x and y unless it's safe to do so), or you need to expose the lock outside the Stash object from peter.petrov's answer, so that both threads can explictly synchronize on that object when they test x > 0 and then call getFromStash() if applicable.
Also, it's generally much harder to figure out thread synchronization when you're using static variables; there tend to be interactions you don't anticipate. You're much better off creating a separate object (e.g. peter.petrov's Stash class) to help you represent the pool, and the pass a reference to it to each of your thread classes. That way all access is via non-static references, and you'll have an easier time making sure you get the code right.
I have a snippet of code that creates 3 threads and expect them to print sequentially using synchronized block on the integer object. But apparently I am getting deadlock sometimes. See below:
public class SequentialExecution implements Runnable {
private Integer i = 1;
public void run() {
String tmp = Thread.currentThread().getName();
if (tmp.equals("first")) {
synchronized(i) {
first();
i = 2;
}
} else if (tmp.equals("second")) {
while (i != 2);
synchronized(i) {
second();
i = 3;
}
} else {
while (i != 3);
synchronized(i) {
third();
}
}
}
public void first() {
System.out.println("first " + i);
}
public void second() {
System.out.println("second " + i);
}
public void third() {
System.out.println("third " + i);
}
public static void main(String[] args) {
//create 3 threads and call first(), second() and third() sequentially
SequentialExecution se = new SequentialExecution();
Thread t1 = new Thread(se, "first");
Thread t2 = new Thread(se, "second");
Thread t3 = new Thread(se, "third");
t3.start();
t2.start();
t1.start();
}
}
The result I am expecting(and sometimes getting) is:
first 1
second 2
third 3
One sample result I am getting with deadlock(and eclipse hangs) is:
first 1
second 2
Anyone know why this is not working? I know I can use locks but I just don't know why using synchronized block is not working.
Declare i to be volatile: private volatile Integer i = 1;. This warns the compiler that it must not apply certain optimizations to i. It must be read from memory each time it is referenced in case another thread has changed it.
I also agree with the recommendation in user3582926's answer to synchronize on this rather than i, because the object referenced by i changes as the program runs. It is neither necessary nor sufficient to make the program work, but it does make it a better, clearer program.
I have tested each change by changing the main method to:
public static void main(String[] args) throws InterruptedException {
// create 3 threads and call first(), second() and third() sequentially
for (int i = 0; i < 1000; i++) {
SequentialExecution se = new SequentialExecution();
Thread t1 = new Thread(se, "first");
Thread t2 = new Thread(se, "second");
Thread t3 = new Thread(se, "third");
t3.start();
t2.start();
t1.start();
t1.join();
t2.join();
t3.join();
}
}
There is no deadlock. There is a memory order issue.
The while loops in the second and third threads are outside any synchronized block. There is nothing telling the compiler and JVM that those threads cannot keep i, or the object to which it points, in a register or cache during the loop. The effect is that, depending on timing, one of those threads may get stuck looping looking at a value that is not going to change.
One way to solve the problem is to mark i volatile. That warns the compiler that it is being used for inter-thread communication, and each thread needs to watch for changes in memory contents whenever i changes.
In order to solve it entirely using synchronization, you need to check the value of the Integer referenced by i inside a block that is synchronized on a single, specific object. i is no good for that, because it changes due to boxing/unboxing conversion. It might as well be a simple int.
The synchronized blocks cannot wrap the while loops, because that really would lead to deadlock. Instead, the synchronized block has to be inside the loop. If the updates to i are synchronized on the same object, that will force the updates to be visible to the tests inside the while loops.
These considerations lead to the following synchronization-based version. I am using a main method that does 1000 runs, and will itself hang if any thread in any of those runs hangs.
public class SequentialExecution implements Runnable {
private int i = 1;
public void run() {
String tmp = Thread.currentThread().getName();
if (tmp.equals("first")) {
synchronized (this) {
first();
i = 2;
}
} else if (tmp.equals("second")) {
while (true) {
synchronized (this) {
if (i == 2) {
break;
}
}
}
synchronized (this) {
second();
i = 3;
}
} else {
while (true) {
synchronized (this) {
if (i == 3) {
break;
}
}
}
synchronized (this) {
third();
}
}
}
public void first() {
System.out.println("first " + i);
}
public void second() {
System.out.println("second " + i);
}
public void third() {
System.out.println("third " + i);
}
public static void main(String[] args) throws InterruptedException {
// create 3 threads and call first(), second() and third() sequentially
for (int i = 0; i < 1000; i++) {
SequentialExecution se = new SequentialExecution();
Thread t1 = new Thread(se, "first");
Thread t2 = new Thread(se, "second");
Thread t3 = new Thread(se, "third");
t3.start();
t2.start();
t1.start();
t1.join();
t2.join();
t3.join();
}
}
}
I believe you want to be using synchronized(this) instead of synchronized(i).
I want to measure how long it takes for the 2 threads to count till 1000. How can I make a benchmark test of the following code?
public class Main extends Thread {
public static int number = 0;
public static void main(String[] args) {
Thread t1 = new Main();
Thread t2 = new Main();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void run() {
for (int i = 0; i <= 1000; i++) {
increment();
System.out.println(this.getName() + " " + getNumber());
}
}
public synchronized void increment() {
number++;
}
public synchronized int getNumber() {
return number;
}
}
And why am I still getting the following result (extract) even though I use the synchronized keyword?
Thread-0 9
Thread-0 11
Thread-0 12
Thread-0 13
Thread-1 10
You are not synchronized. The synchronized keyword is an equivalent to synchonize (this) {} but you are increasing a static number which is not contained within your object. You actually have 2 objects/threads and both of them synchronize with themself, not with each other.
Either make you property volatile and don't synchronize at all or use a lock Object like this:
public static int number = 0;
public static final Object lock = new Object();
public void increment() {
synchronized (lock) {
number++;
}
}
public int getNumber() {
synchronized (lock) {
return number;
}
}
Output is not synchronized. The scenario is:
Thread-0 runs 9 iterations alone.
Thread-1 calls increment and getNumber, which returns 10.
Thread-0 runs three more iterations.
Thread-1 calls println with 10.
You are not synchronizing this:
for (int i = 0; i <= 1000; i++) {
increment();
System.out.println(this.getName() + " " + getNumber());
}
So, a thread can execute increment(), wait for the next thread, and after that keep with getValue() (thus getting your results). Given how fast is adding a value, changing a thread gives the other time for several iterations.
Do
public static final String LOCK = "lock";
synchronized(LOCK) {
for (int i = 0; i <= 1000; i++) {
increment();
System.out.println(this.getName() + " " + getNumber());
}
}
you do not need the synchronize for the methods (as I explain in my comment).
why am I still getting the following result (extract) even though I use the synchronized keyword?
You synchronize access to the number variable, however the increment and get are synchronized separately, and this does not make your println() atomic either. This sequence is perfectly possible:
0 -> inc
1 -> inc
0 -> getnumber
1 -> getnumber
1 -> print
0 -> print
First, if you want to solve the "increment and get" problem, you can use an AtomicInteger:
private static final AtomicInteger count = new AtomicInteger(0);
// ...
#Override
public void run()
{
final String me = getName();
for (int i = 0; i < 1000; i++)
System.out.println(me + ": " + count.incrementAndGet());
}
However, even this will not guarantee printing order. With the code above, this scenario is still possible:
0 -> inc
0 -> getnumber
1 -> inc
1 -> getnumber
1 -> print
0 -> print
To solve this problem, you need to use, for instance, a ReentrantLock:
private static final Lock lock = new ReentrantLock();
private static int count;
// ...
#Override
public void run()
{
final String me = getName;
for (int i = 0; i < 1000; i++) {
// ALWAYS lock() in front of a try block and unlock() in finally
lock.lock();
try {
count++;
System.out.println(me + ": " + count);
finally {
lock.unlock();
}
}
}