Reputation: 3549
I read that volatile variable copy will shared by all the threads and once completion of the execution, the update value will get by every thread,But in the following program using thread pool not giving the output which I expected, can any one tell me the reason?
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Task implements Runnable{
volatile int v1=10;
private String name;
public Task(String name) {
this.name=name;
}
public synchronized void run() {
v1=v1+10;
System.out.println(name +"is entered "+v1);
}
}
public class ThreadPoolTest {
public static void main(String[] args) {
Runnable r1 = new Task("Thread 1");
Runnable r2 = new Task("Thread 2");
Runnable r3 = new Task("Thread 3");
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.execute(r1);
executor.execute(r2);
executor.execute(r3);
executor.shutdown();
}
}
outPut:
Thread 1is entered 20
Thread 2is entered 20
Thread 3is entered 20
but if we change from volatile to static its giving below output:
Thread 1is entered 20
Thread 3is entered 30
Thread 2is entered 40
Upvotes: 2
Views: 222
Reputation: 363
To be short, volatile or Atomic Variables are the solutions to solve the inconsistency(Memory Consistency Errors) when two or more threads try to access the same resource(can be static/non-static) simultaneously.
https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html
In your case, you are not sharing your task with more than one Threads. so no need of using volatile keyword or Atomic variables. if you want to share your variable with more than one thread, then you can use Atomic variables over volatile.
then what happens, when you add static keyword to a variable?
static variables are available to all objects of that class.
https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html
Upvotes: 1
Reputation: 16908
The observed result is correct as you are creating three separate Task
instances who are having their own copy of the name
variable.
So although they are volatile
the values are not updated by other threads the thread executing the particular instance is the one which is updating the v1
field.
If the v1
is made static then it becomes a class
member so obviously the threads will update the same copy of the variable v1
.
Instead of using synchronized
on the run
method, we can use the AtomicInteger
to safely update and fetch the value.
class Task implements Runnable{
private final AtomicInteger v1 = new AtomicInteger(10);
private String name;
public void run() {
System.out.println("Thread is: " + Thread.currentThread().getName() + " " + v1.addAndGet(10));
}
}
public class ThreadPoolTest{
public static void main(String[] args) {
Runnable r1 = new Task();
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.execute(r1);
executor.execute(r1);
executor.execute(r1);
executor.shutdown();
}
}
Upvotes: 4
Reputation: 9521
This is because v1
is an instance variable and each task has its own.
So in the example you incremented v1
of different instances. static
also is not reliable since you are sinchronizing on the instance of a Task
so it still has a race condition (e.g. each thread may read v1
's value to be 10 even in case of static volatile
)
Probably you need AtomicInteger
Upvotes: 2