While learning Java concurrency I ran into this behaviour which I can't explain:
public class ThreadInterferrence implements Runnable {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new ThreadInterferrence());
t.start();
append("1", 50);
t.join();
System.out.println(value);
}
private static String value = "";
public void run() {
append("2", 50);
}
private static void append(String what, int times) {
for (int i = 0; i < times; ++i) {
value = value + what;
}
}
}
Why does the program generate random Strings? More importantly why does the length of output vary? shouldn't it always be exactly 100 chars?
Output examples:
22222222222222222222222222222222222222222222222222
1111111111111111111111111111112121112211221111122222222222222
etc..
Reason is you have two threads.
Main thread which is appending to same value string
ThreadInterferrence Thread which is appending again to same value String.
It's Operating System (OS) who is scheduling which thread to run when and hence you see random output. So in your case, OS schedules your runnable to run for a time being which prints 1 and then tries to run main thread which in turn prints 2.
On the topic of your updated question (why does the length of output vary? shouldn't it always be exactly 100 chars?)
The behavior will be unpredictable, since the re-assignment of the new String is not atomic. Note that Strings are immutable and you keep reassinging a value to a variable. So what is happening is one thread gets the value, the other thread also gets the value, one thread adds a character and writes it again but so does the other thread with the old value. Now you're losing data because the update from one of the threads is lost.
In such a case you could use a StringBuffer which is thread-safe, or add synchronization which I'm sure you'll learn about.
[Question] More importantly why does the length of output vary?
[Answer] The variable "value" is being used by multiple threads (Main thread as well as the other thread). Hence the method which is used to change the state of the variable needs to be thread safe to control the final length. That is not the case here.
Related
I understood that reading and writing data from multiple threads need to have a good locking mechanism to avoid data race. However, one situation is: If multiple threads try to write to a single variable with a single value, can this be a problem.
For example, here my sample code:
public class Main {
public static void main(String[] args) {
final int[] a = {1};
while(true) {
new Thread(new Runnable() {
#Override
public void run() {
a[0] = 1;
assert a[0] == 1;
}
}).start();
}
}
}
I have run this program for a long time, and look like everything is fine. If this code can cause the problem, how can I reproduce that?
Your test case does not cover the actual problem. You test the variable's value in the same thread - but that thread already copied the initial state of the variable and when it changes within the thread, the changes are visible to that thread, just like in any single-threaded applications. The real issue with write operations is how and when is the updated value used in the other threads.
For example, if you were to write a counter, where each thread increments the value of the number, you would run into issues. An other problem is that your test operation take way less time than creating a thread, therefore the execution is pretty much linear. If you had longer code in the threads, it would be possible for multiple threads to access the variable at the same time. I wrote this test using Thread.sleep(), which is known to be unreliable (which is what we need):
int[] a = new int[]{0};
for(int i = 0; i < 100; i++) {
final int k = i;
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(20);
} catch(InterruptedException e) {
e.printStackTrace();
}
a[0]++;
System.out.println(a[0]);
}
}).start();
}
If you execute this code, you will see how unreliable the output is. The order of the numbers change (they are not in ascending order), there are duplicates and missing numbers as well. This is because the variable is copied to the CPU memory multiple times (once for each thread), and is pasted back to the shared ram after the operation is complete. (This does not happen right after it is completed to save time in case it is needed later).
There also might be some other mechanics in the JVM that copy the values within the RAM for threads, but I'm unaware of them.
The thing is, even locking doesn't prevent these issues. It prevents threads from accessing the variable at the same time, but it generally doesn't make sure that the value of the variable is updated before the next thread accesses it.
I have written a short program in order to check the effect of the race condition. Class Counter is given below. The class has two methods to update the counter instance variable c. On purpose, I added a random code in both methods , see related code variable i, to increase the probability of their interleaved execution when accessed by two threads.
In the main() method of my program, I put in a loop the following code
t1=new Thread() { public void run(){objCounter.increment();}};
t2=new Thread() { public void run(){objCounter.decrement();}};
t1.start();
t2.start();
try{
t1.join();
t2.join();
}
catch (InterruptedException IE) {}
Then I printed the different values of c in the objCount... Further to the expected values 1, 0, -1, the program displays also the unexpected values: -2,-1, -3, even 4
I sincerely can't see what threads interleaving will lead to the unexpected values given above. Ideally, I should look at the assembly code to see how the statements c++, and c-- got translated...regardless, I Think there is another reason behind the unexpected values.
class Counter{
private volatile int c=0;
public void increment(){
int i=9;
i=i+7;
c++;
i=i+3;
}
public void decrement() {
int i=9;
i=i+7;
c--;
i=i+3;
}
public int value(){ return c; }
}
Even if you marked an int as volatile, that kind of operations are not atomic. Try to replace your primitive int with a Thread Safe Class like:
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicInteger.html
Or just access it through a synchronyzed method.
I put in a loop the following code
You don't show reinitialization of the objCounter variable; this suggests that you're reusing the variable between loop iterations.
As such, you can get -2 from the situation resulting in -1 (e.g. Thread 1 read, Thread 2 read, T1 write, T2 write) happening twice.
In order to avoid reusing the state from previous runs, you should declare and initialize the objCounter variable inside the loop:
for (...) {
Counter objCounter = new Counter();
t1=new Thread() { public void run(){objCounter.increment();}};
t2=new Thread() { public void run(){objCounter.decrement();}};
// ... Start/join the threads.
}
It can't be declared before the loop and initialized inside the loop, because then it is not effectively final, which is required (that, or actual finality) to refer to it inside the anonymous classes of the threads.
On purpose, I added a random code in both methods , see related code variable i, to increase the probability of their interleaved execution when accessed by two threads.
As an aside, this your random code does nothing of the sort.
There is no requirement for Java to execute the statements in program order, only to appear to execute them in the program order from the perspective of the current thread.
These statements may be executed before or after the c++/--, if they are executed at all - they could simply be detected as useless.
You may as well just remove this code, it really only serves to obfuscate.
I'm learning multithreading. Can anyone tell why here the output is always 100, even though there are two threads which are doing 100 increments?
public class App {
public static int counter = 0;
public static void process() {
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 100; ++i) {
++counter;
}
}
});
Thread thread2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 100; ++i) {
++counter;
}
}
});
thread1.start();
thread2.start();
}
public static void main(String[] args) {
process();
System.out.println(counter);
}
}
The output is 100.
You're only starting the threads, not waiting for them to complete before you print the result. When I run your code, the output is 0, not 100.
You can wait for the threads with
thread1.join();
thread2.join();
(at the end of the process() method). When I add those, I get 200 as output. (Note that Thread.join() throws an InterruptedException, so you have to catch or declare this exception.)
But I'm 'lucky' to get 200 as output, since the actual behaviour is undefined as Stephen C notes. The reason why is one of the main pitfalls of multithreading: your code is not thread safe.
Basically: ++counter is shorthand for
read the value of counter
add 1
write the value of counter
If thread B does step 1 while thread A hasn't finished step 3 yet, it will try to write the same result as thread A, so you'll miss an increment.
One of the ways to solve this is using AtomicInteger, e.g.
public static AtomicInteger counter = new AtomicInteger(0);
...
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 100; ++i) {
counter.incrementAndGet();
}
}
});
Can anyone tell why here the output is always 100, even though there are two threads which are doing 100 increments?
The reason is that you have two threads writing a shared variable and a third reading, all without any synchronization. According to the Java Memory Model, this means that the actual behavior of your example is unspecified.
In reality, your main thread is (probably) printing the output before the second thread starts. (And apparently on some platforms, it prints it before the first one starts. Or maybe, it is seeing a stale value for counter. It is a bit hard to tell. But this is all within the meaning of unspecified)
Apparently, adding join calls before printing the results appears to fix the problem, but I think that is really by luck1. If you changed 100 to a large enough number, I suspect that you would find that incorrect counter values would be printed once again.
Another answer suggests using volatile. This isn't a solution. While a read operation following a write operation on a volatile is guaranteed to give the latest value written, that value may be a value written by another thread. In fact the counter++ expression is an atomic read followed by an atomic write ... but the sequence is not always atomic. If two or more threads do this simultaneously on the same variable, they are liable to lose increments.
The correct solutions to this are to either using an AtomicInteger, or to perform the counter++ operations inside a synchronized block; e.g.
for (int i = 0; i < 100; ++i) {
synchronized(App.class) {
++counter;
}
}
Then it makes no difference that the two threads may or may not be executed in parallel.
1 - What I think happens is that the first thread finishes before the second thread starts. Starting a new thread takes a significant length of time.
In Your case, There are three threads are going to execute: one main, thread1 and thread2. All these three threads are not synchronised and in this case Poor counter variable behaviour will not be specific and particular.
These kind of Problem called as Race Conditions.
Case1: If i add only one simple print statement before counter print like:
process();
System.out.println("counter value:");
System.out.println(counter);
in this situation scenario will be different. and there are lot more..
So in these type of cases, according to your requirement modification will happen.
If you want to execute one thread at time go for Thread join like:
thread1.join();
thread2.join();
join() is a Thread class method and non static method so it will always apply on thread object so apply join after thread start.
If you want to read about Multi threading in java please follow; https://docs.oracle.com/cd/E19455-01/806-5257/6je9h032e/index.html
You are checking the result before threads are done.
thread1.start();
thread2.start();
try{
thread1.join();
thread2.join();
}
catch(InterruptedException e){}
And make counter variable volatile.
I have a static Array, arr, whose elements are getting squarred and stored back again using the 'squarring' method. I want two threads to simultaneously modify the array. Each thread works on half of the array.
public class SimplerMultiExample {
private static int[] arr = new int[10];
public static void squarring(int start, int end)
{
for(int i=start; i<end; i++)
{
arr[i]*=arr[i];
System.out.println("here "+Thread.currentThread().getName());
}
}
private static Runnable doubleRun = new Runnable() {
#Override
public void run() {
if(Integer.parseInt(Thread.currentThread().getName())==1)
squarring(0,arr.length/2); //Thread named "1" is operaing on
//the 1st half of the array.
else
squarring(arr.length/2,arr.length);
}
};
public static void main(String[] args){
Thread doubleOne = new Thread(doubleRun);
doubleOne.setName("1");
Thread doubleTwo = new Thread(doubleRun);
doubleTwo.setName("2");
doubleOne.start();
doubleTwo.start();
}
}
The sysout in the 'squarring' method tells me that the threads are going into the method serially, that is, one of threads finishes before the other one accesses it. As a result, one of the threads finishes early whereas the other ones takes considerably longer to complete. I have tested the code with 1 million elements. Please advice on what I can do to ensure that the threads operate in parallel.
P.S - I am using a dual core system.
You don't have to program this from scratch:
Arrays.parallelSetAll(arr, x -> x * x);
parallelSetAll creates a parallel stream which does all the work for you:
Set all elements of the specified array, in parallel, using the provided generator function to compute each element.
If you'd like to know how to control the number of threads used for parallel processing, checkout this question.
I recommend you add the following code to the end of your main method to ensure they each finish their work:
try {
doubleOne.join(); //Waits for this thread to die.
doubleTwo.join(); //Waits for this thread to die.
} catch (InterruptedException e) {
e.printStackTrace();
}
You are creating two threads that could be executed in parallel provided that the scheduler chooses to interleave them. However, the scheduler is not guaranteed to interleave the execution. Your code works in parallel on my system (...sometimes.. but other times, the threads execute in series).
Since you are not waiting for the threads to complete (using the join method), it is less likely that you would observe the interleaving (since you only observe part of the program's execution).
I have read article concerning atomic operation in Java but still have some doubts needing to be clarified:
int volatile num;
public void doSomething() {
num = 10; // write operation
System.out.println(num) // read
num = 20; // write
System.out.println(num); // read
}
So i have done w-r-w-r 4 operations on 1 method, are they atomic operations? What will happen if multiple threads invoke doSomething() method simultaneously ?
An operation is atomic if no thread will see an intermediary state, i.e. the operation will either have completed fully, or not at all.
Reading an int field is an atomic operation, i.e. all 32 bits are read at once. Writing an int field is also atomic, the field will either have been written fully, or not at all.
However, the method doSomething() is not atomic; a thread may yield the CPU to another thread while the method is being executing, and that thread may see that some, but not all, operations have been executed.
That is, if threads T1 and T2 both execute doSomething(), the following may happen:
T1: num = 10;
T2: num = 10;
T1: System.out.println(num); // prints 10
T1: num = 20;
T1: System.out.println(num); // prints 20
T2: System.out.println(num); // prints 20
T2: num = 20;
T2: System.out.println(num); // prints 20
If doSomething() were synchronized, its atomicity would be guaranteed, and the above scenario impossible.
volatile ensures that if you have a thread A and a thread B, that any change to that variable will be seen by both. So if it at some point thread A changes this value, thread B could in the future look at it.
Atomic operations ensure that the execution of the said operation happens "in one step." This is somewhat confusion because looking at the code 'x = 10;' may appear to be "one step", but actually requires several steps on the CPU. An atomic operation can be formed in a variety of ways, one of which is by locking using synchronized:
What the volatile keyword promises.
The lock of an object (or the Class in the case of static methods) is acquired, and no two objects can access it at the same time.
As you asked in a comment earlier, even if you had three separate atomic steps that thread A was executing at some point, there's a chance that thread B could begin executing in the middle of those three steps. To ensure the thread safety of the object, all three steps would have to be grouped together to act like a single step. This is part of the reason locks are used.
A very important thing to note is that if you want to ensure that your object can never be accessed by two threads at the same time, all of your methods must be synchronized. You could create a non-synchronized method on the object that would access the values stored in the object, but that would compromise the thread safety of the class.
You may be interested in the java.util.concurrent.atomic library. I'm also no expert on these matters, so I would suggest a book that was recommended to me: Java Concurrency in Practice
Each individual read and write to a volatile variable is atomic. This means that a thread won't see the value of num changing while it's reading it, but it can still change in between each statement. So a thread running doSomething while other threads are doing the same, will print a 10 or 20 followed by another 10 or 20. After all threads have finished calling doSomething, the value of num will be 20.
My answer modified according to Brian Roach's comment.
It's atomic because it is integer in this case.
Volatile can only ganrentee visibility among threads, but not atomic. volatile can make you see the change of the integer, but cannot ganrentee the integration in changes.
For example, long and double can cause unexpected intermediate state.
Atomic Operations and Synchronization:
Atomic executions are performed in a single unit of task without getting affected from other executions. Atomic operations are required in multi-threaded environment to avoid data irregularity.
If we are reading/writing an int value then it is an atomic operation. But generally if it is inside a method then if the method is not synchronized many threads can access it which can lead to inconsistent values. However, int++ is not an atomic operation. So by the time one threads read it’s value and increment it by one, other thread has read the older value leading to wrong result.
To solve data inconsistency, we will have to make sure that increment operation on count is atomic, we can do that using Synchronization but Java 5 java.util.concurrent.atomic provides wrapper classes for int and long that can be used to achieve this atomically without usage of Synchronization.
Using int might create data data inconsistencies as shown below:
public class AtomicClass {
public static void main(String[] args) throws InterruptedException {
ThreardProcesing pt = new ThreardProcesing();
Thread thread_1 = new Thread(pt, "thread_1");
thread_1.start();
Thread thread_2 = new Thread(pt, "thread_2");
thread_2.start();
thread_1.join();
thread_2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ThreardProcesing implements Runnable {
private int count;
#Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count++;
}
}
public int getCount() {
return this.count;
}
private void processSomething(int i) {
// processing some job
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
OUTPUT: count value varies between 5,6,7,8
We can resolve this using java.util.concurrent.atomic that will always output count value as 8 because AtomicInteger method incrementAndGet() atomically increments the current value by one. shown below:
public class AtomicClass {
public static void main(String[] args) throws InterruptedException {
ThreardProcesing pt = new ThreardProcesing();
Thread thread_1 = new Thread(pt, "thread_1");
thread_1.start();
Thread thread_2 = new Thread(pt, "thread_2");
thread_2.start();
thread_1.join();
thread_2.join();
System.out.println("Processing count=" + pt.getCount());
}
}
class ThreardProcesing implements Runnable {
private AtomicInteger count = new AtomicInteger();
#Override
public void run() {
for (int i = 1; i < 5; i++) {
processSomething(i);
count.incrementAndGet();
}
}
public int getCount() {
return this.count.get();
}
private void processSomething(int i) {
// processing some job
try {
Thread.sleep(i * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Source: Atomic Operations in java