I am learning Threads synchronization in java and I have the following code :
class abs{
int x=0;
public void increment(){
for(int i =0 ; i<10 ; i++) {
//System.out.println(Thread.currentThread().getId());
x++;
System.out.println(x);
}
}
}
class thread_creation extends Thread{
abs t;
thread_creation(abs x){
t=x;
}
public void run() {
t.increment();
}
}
public class Test_sync {
public static void main(String[] args) {
abs ob = new abs();
thread_creation t1 = new thread_creation(ob);
thread_creation t2 = new thread_creation(ob);
t1.start();
t2.start();
}
}
When I run the code , I get the following output :
2
3
4
5
6
7
8
9
10
11
2
12
13
14
15
16
17
18
19
20
I have many questions regarding this output :
Why the output didn't start with 1 ? Initially x= 0 , so when the first thread increments and output x , then we should see 1 in the output ?
Why the output has value of 2 twice ?
I am very confused , so someone please explain why we got this output ?
Because the threads use a single variable to count.
A x+=1 (1)
B x+=1 (2)
A starts print (2), and goes to sleep
B prints 2
B keeps working, incrementing x, printing 3 to 11
B goes to sleep
A finishes the print of "2" it started a while back
Clarification of followup questions:
x is owned by the object ob of class abs there is only one which is shared across threads.
i is owned by the function public void increment() and there are two independent calls of it.
As to the behaviour of sleeping on printing... That's pretty much the whole point of threads. print takes forever from a cpu point of view and there are exclusive assets (there is only one console) involved
Not a full answer, but responding to a comment:
Why both threads don't share the loop counter variable i?...
That's because i is a local variable within the increment() method. Each call to increment() gets its own distinct i, which is created when the method is called, and which lives only until the method returns.
...although they share the variable x ?
Your x on the other hand is a member variable (a.k.a., a field) of the abs class. Each instance of the abs class gets its own distinct x, and that x lives as long as the instance lives. Your main() method creates just one instance of abs, and gives it to both threads.
What sets the two variables apart is where they are declared. i is declared inside the increment() method body. That's what makes it local. x is declared outside of any method, but inside the declaration of class abs {...}. That's what makes it an instance variable.*
* There are also static variables that can be declared inside a class, but I won't go in to that here.
Related
This question already has answers here:
What is a StackOverflowError?
(16 answers)
Closed 1 year ago.
I'm using a parallel recursion to evaluate if a number is odd or even. I used long type but I'm running into StackOverflowError when input number(x) has 5 digits or more. I don't get why.
static boolean Odd(long n) {
if (n == 0) return false;
else return Even(n - 1);
}
static boolean Even(long d) {
if (d == 0) return true;
else return Odd(d - 1);
}
public static void main(String[] args) {
long x = 0;
while(x>=0) {
System.out.println("Insert number");
x = SavitchIn.readLong();
boolean isOdd = Odd(x);
if(isOdd) {
System.out.println("Odd number");
}else {
System.out.println("Even number");
}
}
}
To understand why you get StackOverflowError, you need to understand what happens when you make a function call in your code and how that is executed in the actual processor.
When you run a program, all of the associated code and symbols are loaded in the memory and then executed one line after another. You have a register called Program Counter which basically acts as a pointer to the current line of code that is executed.
However, when the line to be executed is a function, the code for the function is not available immediately on the next memory address. Rather, this function will be available at a different location in memory. So when the processing unit sees a function call, it copies several important stats like the Program Counter [PC] (to know how far along the code has been executed), register values, etc., and pushes this data into a stack. The reason this data structure is a stack can be explained with the following simple code example:
public class Example {
public int func1() {
int a = 10, b = 20;
int c = a+b;
return c;
}
public int func2() {
int a = 100;
int b = func1();
return a*b;
}
public static void main(String args[]) {
int attr = 10;
int result = func2() / 10;
System.out.println(result);
}
}
In this example, as you know, code execution starts at ```main```` function. So line 1 of the main function is executed and sets the attr variable to 10. Then it goes to line 2 and here, it sees that there is a function call namely func2.
So at this time, the system will push the PC, and other memory into the stack, and then move to the location of func2. In func2, line 1 is executed setting the value of a to 100. Line 2 of func2 is again a function call and hence again all the data is now again pushed onto the stack on top of the previous push and func1 is executed.
In func1, we have no function calls and hence no more stack pushes happen. Func1 has 3 lines of code which get executed one after the other. However, just because we reached the end of func1, it does not mean that we have finished executing the code. We still have to execute the rest of func2 and main. The first set of code we need to execute is func2 because func2 called func1. This is exactly what we have in the stack as well (the top of the stack has func2 values). So we pop it, continue executing func2 and once that is done, we go back to the stack and see there is an entry from the main function. So we pop that out and complete execution.
Now that we have this bit of understanding, in your code, you see that the Odd() and Even() method call each other recursively. For a small number of 5, we see the following happening:
Main(
-push-> Odd(5
-push-> Even(4
-push-> Odd(3
-push-> Even(2
-push-> Odd(1
-push-> Even(0
[return's true]
) -pop->
) -pop->
) -pop->
) -pop->
) -pop->
) -pop->
)
So in this case, for a small number like 5, we see that the size of the stack goes as high as 6. Now for a 5 digit number like 99999, the maximum size of the stack will be 100000 which is an extremely large number for the stack. Remember that for every stack entry, we will be copying the PC, registers, etc. on the stack.
This is why you see a StackOverflowError for 5 digit numbers. The size of the stack becomes very high when the number of digits is 5 which is probably beyond the capabilities of the processor that is running your code.
I'm trying to run four threads. run() method has a for loop that loops 10 times.In each loop the shared resource "x" is increment by 1. When all threads die, the for loop should have run 4x10 =40 times and x value should equal 40.
That is not happening in all runs of the my code.Each time I run the code it prints a different value of x.Most of the output values of x range from 33 to 40.
Why is it not 40 in every run? Does that mean some for loop loops are being skipped? Is it caused due being blocked?
NOTE : this does not happen when sleep() is removed. It prints 40 every single time.
My code :
public class MyThreadImplementsRunnable implements Runnable{
int x =0;
public void run() {
for(int i=0;i<10;i++){
x = x+1;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
System.out.println("exception");
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyThreadImplementsRunnable m = new MyThreadImplementsRunnable();
Thread t1 = new Thread(m,"first");
Thread t2= new Thread(m,"second");
Thread t3= new Thread(m,"third");
Thread t4= new Thread(m,"fourth");
t1.start();
t2.start();
t3.start();
t4.start();
//To make sure not to go the next statement unless all threads die
while(t1.isAlive()|| t2.isAlive()|| t3.isAlive()||t4.isAlive()){
}
//After all threads die
System.out.println("now all threads are dead");
//value of the shared resource x after all threads exit
System.out.println(m.x);
}
}
Some test runs gave the following results :
Output:
now all threads are dead
34
Output:
now all threads are dead
33
x = x + 1 loads the value of x from memory, adds 1 to it and then stores it in x. Lets say Thread t1 loads 30 and at the same time thread t2 loads 30 they both increment 30 by 1 and store 31 in x instead of 32.
Why it's always 40 without sleep can be caused by many things I hypothesize that it's caused by each of the threads running very quickly and finishing before the next one starts.
You also don't use volatile and there are visibility issues but for now lets not get into that. This is also something you need to learn if you want to write multi-threaded code.
You are using a shared resource(x) between threads which is bound to create many problems like data race, visibility.. Your answer will be always different
#oleg I don't think Volatile will help in this scenario
I am running the below class .
public class RunThreads implements Runnable {
static int i;
public static void main(String[] args) {
RunThreads job = new RunThreads();
Thread alpha = new Thread(job);
Thread beta = new Thread(job);
alpha.setName("Alpha");
beta.setName("beta");
alpha.start();
beta.start();
}
public void run(){
for(;i<10;i++){
System.out.println(Thread.currentThread().getName() + i);
}
}
}
And my output is :
beta0
beta1
Alpha0
beta2
beta4
beta5
beta6
Alpha3
Alpha8
beta7
Alpha9
I understand I will get different outputs every time I execute it. My question is, why does the output have the value of i as 0 twice, for both the alpha and beta threads i.e. Alpha0 and beta0.
The value of i has been incremented to 1 by the beta thread. So, how does the alpha thread print out Alpha0
I maybe missing something very obvious here. Thanks !
Things are scary when you access shared data with no synchronization etc:
There's no guarantee that the Alpha thread reading i will see the "latest" update from the beta thread or vice versa
It's possible for both threads to start i++ at roughly the same time... and as i++ is basically:
int tmp = i;
tmp++;
i = tmp;
you can easily "lose" increments
If you want to make this thread-safe, you should use AtomicInteger instead:
import java.util.concurrent.atomic.AtomicInteger;
public class RunThreads implements Runnable {
static AtomicInteger counter = new AtomicInteger();
public static void main(String[] args) {
RunThreads job = new RunThreads();
Thread alpha = new Thread(job);
Thread beta = new Thread(job);
alpha.setName("Alpha");
beta.setName("beta");
alpha.start();
beta.start();
}
public void run(){
int local;
while ((local = counter.getAndIncrement()) < 10) {
System.out.println(Thread.currentThread().getName() + local);
}
}
}
Your output may still appear to be in the wrong order (because the alpha thread may "start" writing "Alpha0" while the beta thread "starts" writing "beta1" but the beta thread gets the lock on console output first), but you'll only see each count once. Note that you have to use the result of getAndIncrement() for both the checking and the printing - if you called counter.get() in the body of the loop, you could still see duplicates due to the interleaving of operations.
The simple answer here would be that whether or not the variable is volatile or atomic or whatever, both your threads start out when the variable value is 0, and only change it after the print.
This means that both threads can reach the "print" line before either of them reached the i++.
Which means that both are very likely to print 0, unless one of them is delayed long enough for the other one to update the variable (at which point the question of memory model and data visibility arise).
"While" thread A is doing its update, thread B is reading that value.
Like in:
A: prints i (current value 0)
B: prints i (current value 0)
A: stores 1 to i
You can't assume that those two actions:
for(;i<10;i++){ // increasing the loop counter
and
System.out.println(Thread.currentThread().getName() + i);
printing the loop counter happen in "one shot". To the contrary.
Both threads execute the corresponding instructions in parallel; and there are absolutely no guarantees on the outcome of that.
Threads might run on separate cores in multicore architecture and each core has it's own registry set or local cache, as long as you don't invalidate a cache the running core might not reach to a RAM memory to get up-to-date value and will use the cached one. To make it work as you expected it the variable would have to be marked as volatile, which would invalidate a cache on each write to this memory location and fetch the value directly from RAM.
Update:
As was pointed in comments - volatile is not enough to keep the value up to date, there is a read and write operation on i++. To make it work AtomicInteger would be enough, or slightly more expensive locking around i++.
In the code below:
I am updating num[1]=0 of an AtomicIntegerArray num 1000 times each in 2 threads.
At the end of the 2 threads in main thread ;shouldn't the value of num[1] be 2000 as there shouldn't be data races in an AtomicIntegerArray .
However I get random values < 2000. Could someone tell me why?
Code:
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicIntegerArr {
private static AtomicIntegerArray num= new AtomicIntegerArray(2);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyRun1());
Thread t2 = new Thread(new MyRun2());
num.set(0, 10);
num.set(1, 0);
System.out.println("In Main num before:"+num.get(1));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("In Main num after:"+num.get(1));
}
static class MyRun1 implements Runnable {
public void run() {
for (int i = 0; i < 1000; i++) {
num.set(1,num.get(1)+1);
}
}
}
static class MyRun2 implements Runnable {
public void run() {
for (int i = 0; i < 1000; i++) {
num.set(1,num.get(1)+1);
}
}
}
}
Edit: Adding num.compareAndSet(1, num.get(1), num.get(1)+1); instead of num.set(1,num.get(1)+1); doesnt work either.
I get random values < 2000. Could someone tell me why?
This is called the lost-update problem.
Because, in the following code:
num.set(1, num.get(1) + 1);
Although each individual operation involved is atomic, the combined operation is not. The single operations from the two threads can interleave, causing updates from one thread to be overwritten with stale value by another thread.
You can use compareAndSet to solve this problem, but you have to check whether the operation is successful, and do it again when it fails.
int v;
do {
v = num.get(1);
} while (!num.compareAndSet(1, v, v+1));
There's also a method for exactly this purpose:
num.accumulateAndGet(1, 1, (x, d)->x+d);
accumulateAndGet(int i, int x, IntBinaryOperator accumulatorFunction)
Atomically updates the element at index i with the results of applying the given function to the current and given values, returning the updated value. The function should be side-effect-free, since it may be re-applied when attempted updates fail due to contention among threads. The function is applied with the current value at index i as its first argument, and the given update as the second argument.
This is a classic race condition. Any time you have a fetch, an operation, and a put, your code is racy.
Consider two threads, both executing num.set(1,num.get(1)+1) at roughly the "same time." First, let's break down what the expression itself is doing:
it fetches num.get(1); let's call this x
it adds 1 to that; let's call this y
it puts that sum in at `num.set(1, y);
Even though the intermediate values in your expression are just values on the stack, and not explicit variables, the operation is the same: get, add, put.
Okay, so back to our two threads. What if the operations are ordered like this?
inital state: n[1] = 5
Thread A | Thread B
========================
x = n[1] = 5 |
| x = n[1] = 5
| y = 5 + 1 = 6
y = 5 + 1 = 6 |
n[1] = 6 |
| n[1] = 6
Since both threads fetched the value before either thread put its added value, they both do the same thing. You have 5 + 1 twice, and the result is 6, not 7!
What you want is getAndIncrement(int idx), or one of the similar methods that does the get, adding, and putting atomically.
These methods can actually all be built on top of the compareAndSet method you identified. But to do that, you need to do the increment within a loop, trying until the compareAndSet returns true. Also, for that to work, you have store that initial num.get(1) value in a local variable, rather than fetching it a second time. In effect, this loop says "keep trying the get-add-put logic until it works without anyone else having raced between the operations." In my example above, Thread B would have noticed that compareAndSet(1, 5, 6) fails (since the actual value at that time is 6, not 5 as expected), and thus retried. This is in fact what all of those atomic methods, like getAndIncrement, do.
I'm studying up for the SCJP exam, upon doing some mock tests I came across this one :
It asks what is the output of the following :
class TestClass
{
int i = getInt();
int k = 20;
public int getInt() { return k+1; }
public static void main(String[] args)
{
TestClass t = new TestClass();
System.out.println(t.i+" "+t.k);
}
}
I thought it would be 21 20, since t.i would invoke getInt, which then increments k to make 21.
However, the answer is 1 20. I don't understand why it would be 1, can anyone shed some light on this?
The variables are initialized from top to bottom.
This is what happens:
Initially both i and k have the (default) value 0.
The value computed by getInt() (which at the time is 0 + 1) is assigned to i
20 is assigned to k
1 20 is printed.
Good reading:
The Java™ Tutorials: Initializing Fields
jvm will follows like this,
1.identification for non-static members from top to bottom
2.executing non-static variables and blocks from top to bottom
3.executing the constructor......
in the first step jvm will provide default values..on that time variables in readindirectly write only state..