How does incrementing a value across multiple threads in Java work? - java

I have two pieces of multithreaded code. One passes an Integer to the thread and the thread increments it and the other passes an object that has an inner Integer which is incremented. When I run these the output is different and not what I expected. Can someone give an explanation of what's going and how I'd make the first behave in a similar manner to the second.
Implementation 1:
public class Main {
public static void main(String[] args) {
Integer counter = 0;
for (int i = 0; i < 3; i++) {
Threaded t = new Threaded("Thread " + i, counter);
Thread thread = new Thread(t);
thread.start();
}
}
}
class Threaded implements Runnable {
private final String name;
private Integer counter;
public Threaded(String name, Integer counter) {
this.name = name;
this.counter = counter;
}
#Override
public void run() {
for (int i = 0; i < 5; i++) {
counter++;
System.out.println(name + ": " + counter);
}
}
}
Output 1:
Thread 1: 1
Thread 1: 2
Thread 0: 1
Thread 0: 2
Thread 0: 3
Thread 0: 4
Thread 0: 5
Thread 2: 1
Thread 2: 2
Thread 2: 3
Thread 2: 4
Thread 1: 3
Thread 1: 4
Thread 1: 5
Thread 2: 5
Implementation 2:
public class Main {
public static void main(String[] args) {
MyObj obj = new MyObj();
for (int i = 0; i < 3; i++) {
Threaded t = new Threaded("Thread " + i, obj);
Thread thread = new Thread(t);
thread.start();
}
}
}
class MyObj {
private int count = 0;
public void inc() { count++; }
public int getCount() { return count; }
}
class Threaded implements Runnable {
private final String name;
private final MyObj obj;
public Threaded(String name, MyObj obj) {
this.name = name;
this.obj = obj;
}
#Override
public void run() {
for (int i = 0; i < 5; i++) {
obj.inc();
System.out.println(name + ": " + obj.getCount());
}
}
}
Output 2:
Thread 1: 2
Thread 1: 3
Thread 1: 4
Thread 1: 5
Thread 1: 6
Thread 0: 1
Thread 0: 7
Thread 2: 8
Thread 0: 9
Thread 2: 10
Thread 2: 11
Thread 0: 12
Thread 2: 13
Thread 2: 15
Thread 0: 14
Is it possible to have multiple threads all increment an Integer directly but get an output similar to implementation 2?

For the first example, each thread has its own counter and it is incremented separately. Integer is immutable, when it is incremented the result is a new Integer object. The threads get the same starting value but there is no shared state.
For the second example the threads share the same MyObject instance, there is nothing to stop them from overwriting each others' work. Use AtomicInteger in the second example and the threads won't interfere with each other.
class MyObj {
private AtomicInteger counter = new AtomicInteger(0);
public void inc() {
counter.incrementAndGet();
}
public int getCount() {
return counter.get();
}
}

Never share unprotected resources across threads
The Answer by Nathan Hughes is correct.
Change this code:
new Threaded( "Thread " + i , obj )
… to this:
new Threaded( "Thread " + i , new MyObject( … ) )
… to get behavior similar to your first example. By passing each new Thread its own instance of MyObject, the various Thread objects will no longer be stepping in each other’s feet.
The lesson here is to never share resources across threads without adding protection. As Nathan Hughes suggested, replacing int on MyObject class with AtomicInteger is one way to add protection. Mark that AtomicInteger as final to ensure that its instance is never replaced.
Executor service
Another issue: In modern Java, we rarely address the Thread class directly. Instead, use the Executors framework added to Java 5.
Define your task as a Runnable or Callable. Pass an instance of that task to an executor service.
The lambda syntax in Java 8+ is often quite convenient to use in defining your Runnable. The code in the lambda can refer to variables in its surrounding code.
This has been covered many times on Stack Overflow. Search to learn more.
Example code
Here is a revamped version of your code using an executor service.
Notice that inc method has been changed to return the newly incremented count rather than returning void. By the time another line of code called the MyObj#getCount, some other thread may have performed an additional increment, so result of getCount would not give your intended results.
package work.basil.threading;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class App2
{
public static void main ( String[] args )
{
App2 app = new App2();
app.demo();
}
private void demo ( )
{
final MyObj myObj = new MyObj();
Runnable task = ( ) -> {
for ( int i = 0 ; i < 5 ; i++ )
{
int newValue = myObj.inc();
// BEWARE: Multi-threaded calls to `System.out` may *not* appear chronologically. Add timestamp to get some idea of chronology.
System.out.println( Thread.currentThread().getId() + " thread incremented to : " + newValue + " at " + Instant.now() );
}
};
ExecutorService executorService = Executors.newCachedThreadPool();
for ( int i = 0 ; i < 3 ; i++ )
{
executorService.submit( task );
}
executorService.shutdown();
try { executorService.awaitTermination( 1 , TimeUnit.MINUTES ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
}
}
class MyObj
{
private final AtomicInteger count = new AtomicInteger();
public int inc ( ) { return this.count.incrementAndGet(); }
public int getCount ( ) { return count.get(); }
}
Example run. Again, beware of the console printing lines out of chronological order.
15 thread incremented to : 1 at 2022-03-04T21:54:17.926156Z
17 thread incremented to : 3 at 2022-03-04T21:54:17.926207Z
16 thread incremented to : 2 at 2022-03-04T21:54:17.926219Z
17 thread incremented to : 5 at 2022-03-04T21:54:17.941980Z
15 thread incremented to : 4 at 2022-03-04T21:54:17.941961Z
16 thread incremented to : 6 at 2022-03-04T21:54:17.942027Z
15 thread incremented to : 8 at 2022-03-04T21:54:17.942054Z
17 thread incremented to : 7 at 2022-03-04T21:54:17.942041Z
16 thread incremented to : 9 at 2022-03-04T21:54:17.942067Z
15 thread incremented to : 10 at 2022-03-04T21:54:17.942083Z
17 thread incremented to : 11 at 2022-03-04T21:54:17.942126Z
16 thread incremented to : 12 at 2022-03-04T21:54:17.942164Z
15 thread incremented to : 13 at 2022-03-04T21:54:17.942176Z
16 thread incremented to : 15 at 2022-03-04T21:54:17.942254Z
17 thread incremented to : 14 at 2022-03-04T21:54:17.942219Z

In a nutshell: The difference between your two implementations is that your MyObj class is mutable, but Integer is immutable.
In particular, this statement does not do what you seem to think it does:
counter++;
What it does is:
fetch the value of the counter variable, which is a reference to an immutable Integer object.
Get the int value of the Integer object,
Compute a new int value, equal to 1+ the previous value,
Construct a new Integer object with the new value, and finally
Store a reference to the new object into the counter variable.
Since each of your threads has its own counter, and each one constructs its own new sequence of Integer objects to assign to counter, the threads run entirely independent of each other.
In your second example, there is only ever one MyObj instance. Each thread has its own obj variable, but those are all initialized to point to the same instance, and the threads never assign their obj variables: The threads mutate the one shared instance instead.

Related

Threads with shared integer object not working as expected

I have a problem where i have to print the numbers in such format.
First 1
First 2
Second 3
Second 4
First 5
First 6
Second 7
Second 8
First 9
and so on...
I have implemented my runnable interface as below.
class ThreadDemo implements Runnable {
public volatile Integer num;
public Object lock;
public ThreadDemo(Integer num, Object lock) {
this.num = num;
this.lock = lock;
}
#Override
public void run() {
try {
while (true) {
int count = 0;
synchronized(lock) {
Thread.sleep(100);
while (count < 2) {
System.out.println(Thread.currentThread().getName() + " " + num++);
count++;
}
lock.notify();
lock.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
My main class is as follows
public class CoWorkingThreads {
private static volatile Integer num = new Integer(1);
public static void main(String...args) {
Object lock = new Object();
Thread thread1 = new Thread(new ThreadDemo(num, lock), "First");
thread1.start();
Thread thread2 = new Thread(new ThreadDemo(num, lock), "Second");
thread2.start();
}
}
when i run the program i am getting the output as follows
First 1
First 2
Second 1
Second 2
First 3
First 4
Second 3
Second 4
Instead of previously expected results. But when I Change the integer to atomic integer type i start getting the expected result. can anyone explain what is i can do to make it run with integer instead of using atomic integer
Java Integer cannot be passed by reference. On your code, each thread will create a copy of the variable. However atomicInteger can be passed by reference.
Also, to get the correct result, you can change the num variable to static variable.
public static Integer num = 1;
public Object lock;
public ThreadDemo(Integer num, Object lock) {
//this.num = num;
this.lock =lock;
}
Your problem is that the Integer class is Immutable, so you cannot use it in separate threads to reference a shared value. Answer: Create your own, Mutable, Integer class.
You can find a similar question answered on SO here
Just for your knowledge, instead of using a synchronized block, on an Object, you might want to experiment with Lock(s) (e.g. ReentrantLock) and their associated Condition(s).
Using Condition(s) you can manage your shared resources in a mutually exclusive way between threads.
I still believe that this question is NOT answered correctly. The flaw here is that you have never marked shared data as static. So each thread has it's own copy independent of the other. Integer is an immutable wrapper class, which is true but it has nothing to do in this context. Let's dig more into num++. The ++ operator applies only to (primitive) integer types. Behind the scenes, num is unboxed, the ++ is applied, and the result is then assigned back to num (after a boxing conversion). The Integer class does not have a ++ operator. In fact, Integer objects are immutable.
Immutable means every time you increment and create a new value object. And that new value object is assigned back to your num reference. But two threads have their own copy of num reference pointing to different Integer boxed primitives. So they increment it independently of one another which is not visible to the other. If you want to share it between threads you have to use static access modifier at the site of declaration. More over a passing two values to a shared variable does not make sense. Instead you can initialize it inline. Here's the fixed version.
public class ThreadDemo implements Runnable {
public static Integer num = 1;
public static final Object lock = new Object();
public ThreadDemo() {
}
#Override
public void run() {
try {
while (true) {
int count = 0;
synchronized (lock) {
Thread.sleep(100);
while (count < 2) {
System.out.println(Thread.currentThread().getName() + " " + num++);
count++;
}
lock.notify();
lock.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class CoWorkingThreads {
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadDemo(), "First");
thread1.start();
Thread thread2 = new Thread(new ThreadDemo(), "Second");
thread2.start();
}
}
Finally use of a client provided lock object violates the encapsulation of synchronization policy. So I have used an internal private lock object instead.
Here's the new output.
First 1 First 2 Second 3 Second 4 First 5 First 6 Second 7
Second 8 First 9 First 10

Java Multi Threading / initiating threads in a loop

Can someone help me to solve this multi-threading problem ?
The program should initiate three threads with a common resource. Each thread should print a incremented count value. Sample output is mentioned below. where T1,T2 and T3 are threads.
T1 T2 T3
1 2 3
4 5 6
7 8 9
My current code:
public class RunnableSample implements Runnable {
static int count = 0;
public void run() {
synchronized (this) {
count++;
System.out.println(
"Current thread : Thread name :" + Thread.currentThread().getName()
+ " Counter value :" + count
);
}
}
}
//main method with for loop for switching between the threads
public class ThreadInitiator {
public static void main(String[] args) {
RunnableSample runnableSample = new RunnableSample();
Thread thread1 = new Thread(runnableSample, "T1");
Thread thread2 = new Thread(runnableSample, "T2");
Thread thread3 = new Thread(runnableSample, "T3");
for (int i = 0; i < 9; i++) {
thread1.start();
thread2.start();
thread3.start();
}
}
}
Create a synchronized method to increment the value. When a method is identified as synchronized, only one thread can access it at a time and the other threads wait for the initial thread to complete method execution before they can access the method.
Pls check How to synchronize a static variable among threads running different instances of a class in java?

Why don't these blocks of code give the same result?

So I'm new to this Thread stuff and I wrote a simple program to test avoiding Race Conditions. My first attempt was with Named Inner classes :
/* App1.java */
package ehsan;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class App1{
private final int poolSize = 10;
private final int numLoop = 5;
private int lastThread = 0;
public App1() {
ExecutorService taskList = Executors.newFixedThreadPool(poolSize);
for (int i = 0;i < poolSize;i++) {
taskList.execute(new Counter());
}
taskList.shutdown();
}
private class Counter implements Runnable{
#Override
public void run() {
synchronized (this) {
int currentThread = lastThread;
System.out.println("Current thread : "+currentThread);
lastThread = lastThread + 1;
}
System.out.println("Thread was executed");
}
}
}
and App1Test.java :
package ehsan;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
new App1();
}
}
So as a result it showed :
Current thread : 0
Thread was executed
Current thread : 1
Thread was executed
Current thread : 1
Thread was executed
Current thread : 3
Thread was executed
Current thread : 4
Thread was executed
Current thread : 5
Thread was executed
Current thread : 6
Thread was executed
Current thread : 7
Thread was executed
Current thread : 6
Current thread : 8
Thread was executed
Thread was executed
And whole things got mixed up and I'm facing Race conditions here even when I've use synchronized there.
But my second attempt worked! :
package ehsan;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class App1 implements Runnable{
private final int poolSize = 10;
private final int numLoop = 5;
private int lastThread = 0;
public App1() {
ExecutorService taskList = Executors.newFixedThreadPool(poolSize);
for (int i = 0;i < poolSize;i++) {
taskList.execute(this);
}
taskList.shutdown();
}
#Override
public void run() {
synchronized (this) {
int currentThread = lastThread;
System.out.println("Current thread : "+currentThread);
lastThread = lastThread + 1;
System.out.println("Thread was executed");
}
}
}
And the result was as I expected :
Current thread : 0
Thread was executed
Current thread : 1
Thread was executed
Current thread : 2
Thread was executed
Current thread : 3
Thread was executed
Current thread : 4
Thread was executed
Current thread : 5
Thread was executed
Current thread : 6
Thread was executed
Current thread : 7
Thread was executed
Current thread : 8
Thread was executed
Current thread : 9
Thread was executed
So my question is why my first attempt didn't work and the second one worked greatly? Thanks for helping me, I'm a beginner in Multi-Threaded programming!
In the first program, you create a different Counter instance as the Runnable whose run() method is executed by each thread, so synchronized (this) uses a different lock for each thread, and therefore the code is not thread safe. If you use the same Counter instance instead of creating a new one for each thread, this program will also behave as you expected.
Counter counter = new Counter();
for (int i = 0;i < poolSize;i++) {
taskList.execute(counter);
}
In the second program, you use the same App1 instance as the Runnable whose run() method is executed by all the threads, so synchronized (this) uses the same locks for all the threads.
With a great deal of research I found few ways to solve this.
Please Note : Some of these solutions were pointed out by Eran, Thomas and etc. and I thank them for helping me but I just wanted to collect all the possible solutions in a single answer so the future visitors of this post find the answers easily.
For Named Inner Classes :
Instead of using this as the locking object for synchronization we can use the OutterClass instance :
synchronized (App1.this) {
int currentThread = lastThread;
System.out.println("Current thread : "+currentThread);
lastThread = lastThread + 1;
}
For Separated Classes :
Solution 1
Synchronizing on an object we are receiving from the Caller Class( The class containing the task list and ... ). Here is an example :
public App1 implements Runnable {
private final Integer shared;/* Not spending time on auto-boxing */
public App1(Integer sharedNum) {
shared = sharedNum;
}
#Override
public void run() {
synchronization(shared){
//code here
}
}
}
public App1Test {
private final int forSharing = 14;
public static void main(String[] args) {
ExecutorService taskList = Executors.newFixedThreadPool(poolSize);
taskList.execute(new App1(forSharing));
// and lob lob
}
}
Solution 2
Synchronization on class object :
synchronized (App1.class) { /* As the fields and methods of class App1 are the same for all objects */
int currentThread = lastThread;
System.out.println("Current thread : "+currentThread);
lastThread = lastThread + 1;
}
Solution 3
Synchronizing on an static field ( Which I loved it because its really innovative ) :
/* Add this field to class definition */
private static Object sharedObject = new Object();
/* Now in `run` method use the object like this : */
synchronized(sharedObject) {
//TODO : write your code here :)
}
So these are the solutions to this sneaky problem which is a bit hard to debug :)
I hope this helps fellows who have faced the same problem :)
Cheers, Ehsan
synchronized (this) in Counter synchronizes on the instance, so if you pass a new instance to each thread (taskList.execute(new Counter());) there won't be any synchronization at all (since no 2 threads use the same instance to synchronize on). Thus either use synchronized(Counter.class) or some other shared monitor object (since Counter is an inner class of App1 you could use synchronize(App1.this)).
Your second approach works since you pass the same instance to each thread: taskList.execute(this);.

Printing numbers in loop with two threads

I am trying out codes with multiple threads.
Below is my code:
package com.thread.practice;
public class ThreadPratice1 {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t1 = new Thread(r, "Thread 1");
Thread t2 = new Thread(r, "Thread 2");
t1.start();
t2.start();
}
}
package com.thread.practice;
public class MyRunnable implements Runnable {
private static int i = 0;
#Override
public void run() {
for(i = 0; i <10;i++){
System.out.println("Thread: "+ Thread.currentThread().getName()
+" value of i: "+i);
try {
//System.out.println("Thread: "+ i);
Thread.sleep(1000);
//System.out.println("inside runnable: "+Thread.currentThread().getState());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
But in the output it is always printing the value of i as 0 twice in the beginning.
Output is coming kind of like this:
Thread: Thread 1 value of i: 0
Thread: Thread 2 value of i: 0
Thread: Thread 1 value of i: 2
Thread: Thread 2 value of i: 2
Thread: Thread 1 value of i: 3
Thread: Thread 2 value of i: 4
Thread: Thread 1 value of i: 5
Thread: Thread 2 value of i: 6
Thread: Thread 1 value of i: 7
Thread: Thread 2 value of i: 8
Thread: Thread 1 value of i: 9
May someone please help me in understanding this issue?
Because the value of i at the begging of the execution of the two threads is 0.
In other words, thread one and thread two stared almost at the same time, so the two of them set the i to 0 for the first loop.
for(i = 0; i <10;i++) {
Then the value changes between thread because you made i static. so it will be shared between your two threads.
You made "i" static, which means it will be the same over all threads and objects. Take away the static modifier and your code will work properly.
edit: I misinterpreted what you asked- don't set i to 0 in the for loop, it will look something like this:
for(;i<10;i++) { /*mycode*/}
One of these two is probably what you want anyway, your question was a little bit vague
value of i is incremented by the for loop only after the loop is executed. Execution of for loop takes a finite amount of time. Since you are starting the threads together (almost), both the threads may or may not print i after the other thread has finished one loop. Since you are not doing to ensure thread safety, the result will be unpredictable like the one you got.
First, You shouldn't use the primitive int type for concurrency, it's not thread safe and it maybe will cause Race Condition,
and try to use AtomicInteger to replace int, it's thread safe. the example maybe:
public class ThreadPratice1 {
public static void main(String[] args) {
AtomicInteger number = new AtomicInteger(0);
MyRunnable r = new MyRunnable(number);
Thread t1 = new Thread(r, "Thread 1");
Thread t2 = new Thread(r, "Thread 2");
t1.start();
t2.start();
}
}
class MyRunnable implements Runnable {
private AtomicInteger number;
public MyRunnable(AtomicInteger number) {
this.number = number;
}
#Override
public void run() {
while (number.get() < 10) {
System.out.println("Thread: " + Thread.currentThread().getName()
+ " value of i: " + number.getAndIncrement());
}
}
}

Why don't these threads run in sequence? [duplicate]

This question already has answers here:
Synchronized block not working
(8 answers)
Closed 7 years ago.
I have difficulty understanding synchronized and reentrant lock. Here is small program I was experimenting with:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Reentr {
public static void main(String[] args) {
ExecutorService eService = Executors.newFixedThreadPool(2);
for (int i = 1; i <= 2; i++) {
eService.execute(new process());
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
eService.shutdown();
}
}
class process implements Runnable {
int count = 0;
#Override
public void run() {
processTest();
}
public synchronized void processTest() {
try {
for (int i = 1; i <= 2; i++) {
count += i;
System.out.println("count value for " + Thread.currentThread().getName() + " is " + count);
}
} finally {
System.out.println("count for " + Thread.currentThread().getName() + " is " + count);
}
}
}
The output was:
count value for pool-1-thread-2 is 1
count value for pool-1-thread-1 is 1
count value for pool-1-thread-2 is 3
count for pool-1-thread-2 is 3
count value for pool-1-thread-1 is 3
count for pool-1-thread-1 is 3
If we see in the output two thread are in the synchronized block. I was under the impression that one thread has to complete the execution of synchronized method, after that other thread will enter the method.
Ideally, I was expecting result something like this
count value for pool-1-thread-1 is 1
count value for pool-1-thread-1 is 3
count for pool-1-thread-1 is 3
count value for pool-1-thread-2 is 1
count value for pool-1-thread-2 is 3
count for pool-1-thread-2 is 3
I have replaced synchronized method with synchronized block and re-entrant locks. However, I still have the same output. What am I missing?
The two threads are not synchonizing on the same object.
You have two different instances of process (as an aside; you should always name classes with a Capital letter). The synchronized keyword is equivalent to:
public void processTest() {
synchronized(this) {
// etc..
}
}
If you want one thread to run after the other, they must synchronize on the same object. If you did this, for example:
class process implements Runnable {
// note that this is static
private static final Object lock = new Object();
public void processTest() {
synchronized(lock) {
// your code
}
}
}
Then your code would have one thread run after the other. Another way to do it would be to pass the lock into the Objects constructor, or the same instance of a Semaphore, etc.
When an instance method is declared synchronized, it synchronizes on the object instance. Since you are running with a new process() in each loop iteration, the object instances are different, so the synchronization is meaningless. Try creating a single process object and passing that to both of the threads you start.
When you do, also move the count instance variable into the processTest method. That way it will be thread safe.

Categories

Resources