Introduction
I have written a very simple program as an attempt to re-introduce myself to multi-threaded programming in JAVA. The objective of my program is derived from this rather neat set of articles, written by Jakob Jankov. For the program's original, unmodified version, consult the bottom of the linked article.
Jankov's program does not System.out.println the variables, so you cannot see what is happening. If you .print the resulting value you get the same results, every time (the program is thread safe); however, if you print some of the inner workings, the "inner behaviour" is different, each time.
I understand the issues involved in thread scheduling and the unpredictability of a thread's Running. I believe that may be a factor in the question I ask, below.
Program's Three Parts
The Main Class:
public class multiThreadTester {
public static void main (String[] args) {
// Counter object to be shared between two threads:
Counter counter = new Counter();
// Instantiation of Threads:
Thread counterThread1 = new Thread(new CounterThread(counter), "counterThread1");
Thread counterThread2 = new Thread(new CounterThread(counter), "counterThread2");
counterThread1.start();
counterThread2.start();
}
}
The objective of the above class is simply to share an object. In this case, the threads share an object of type Counter:
Counter Class
public class Counter {
long count = 0;
// Adding a value to count data member:
public synchronized void add (long value) {
this.count += value;
}
public synchronized long getValue() {
return count;
}
}
The above is simply the definition of the Counter class, which includes only a primitive member of type long.
CounterThread Class
Below, is the CounterThread class, virtually unmodified from the code provided by Jankov. The only real difference (despite my implementing Runnable as opposed to extending Thread) is the addition of System.out.println(). I added this to watch the inner-workings of the program.
public class CounterThread implements Runnable {
protected Counter counter = null;
public CounterThread(Counter aCounter) {
this.counter = aCounter;
}
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("BEFORE add - " + Thread.currentThread().getName() + ": " + this.counter.getValue());
counter.add(i);
System.out.println("AFTER add - " + Thread.currentThread().getName() + ": " + this.counter.getValue());
}
}
}
Question
As you can see, the code is very simple. The above code's only purpose is to watch what happens as two threads share a thread-safe object.
My question comes as a result of the output of the program (which I have tried to condense, below). The output is hard to "get consistent" to demonstrate my question, as the spread of the difference (see below) can be quite great:
Here's the condensed output (trying to minimize what you look at):
AFTER add - counterThread1: 0
BEFORE add - counterThread1: 0
AFTER add - counterThread1: 1
BEFORE add - counterThread1: 1
AFTER add - counterThread1: 3
BEFORE add - counterThread1: 3
AFTER add - counterThread1: 6
BEFORE add - counterThread1: 6
AFTER add - counterThread1: 10
BEFORE add - counterThread2: 0 // This BEFORE add statement is the source of my question
And one more output that better demonstrates:
BEFORE add - counterThread1: 0
AFTER add - counterThread1: 0
BEFORE add - counterThread1: 0
AFTER add - counterThread1: 1
BEFORE add - counterThread2: 0
AFTER add - counterThread2: 1
BEFORE add - counterThread2: 1
AFTER add - counterThread2: 2
BEFORE add - counterThread2: 2
AFTER add - counterThread2: 4
BEFORE add - counterThread2: 4
AFTER add - counterThread2: 7
BEFORE add - counterThread2: 7
AFTER add - counterThread2: 11
BEFORE add - counterThread1: 1 // Here, counterThread1 still believes the value of Counter's counter is 1
AFTER add - counterThread1: 13
BEFORE add - counterThread1: 13
AFTER add - counterThread1: 16
BEFORE add - counterThread1: 16
AFTER add - counterThread1: 20
My question(s):
Thread safety ensures the safe mutability of a variable, i.e. only one thread can access an object at a time. Doing this ensures that the "read" and "write" methods will behave, appropriately, only writing after a thread has released its lock (eliminating racing).
Why, despite the correct write behaviour, does counterThread2 "believe" Counter's value (not the iterator i) to still be zero? What is happening in memory? Is this a matter of the thread containing it's own, local Counter object?
Or, more simply, after counterThread1 has updated the value, why does counterThread2 not see - in this case, System.out.println() - the correct value? Despite not seeing the value, the correct value is written to the object.
Why, despite the correct write behaviour, does counterThread2 "believe" Counter's value to still be zero?
The threads interleaved in such a way to cause this behaviour. Because the print statements are outside of the synchronised block, it is possible for a thread to read the counter value then pause due to is scheduling while the other thread increments multiple times. When the waiting thread finally resumes and enters the inc counter method, the value of the counter will have moved on quite a bit and will no longer match what was printed in the BEFORE log line.
As an example, I have modified your code to make it more evident that both threads are working on the same counter. First I have moved the print statements into the counter, then I added a unique thread label so that we can tell which thread was responsible for the increment and finally I only increment by one so that any jumps in the counter value will stand out more clearly.
public class Main {
public static void main (String[] args) {
// Counter object to be shared between two threads:
Counter counter = new Counter();
// Instantiation of Threads:
Thread counterThread1 = new Thread(new CounterThread("A",counter), "counterThread1");
Thread counterThread2 = new Thread(new CounterThread("B",counter), "counterThread2");
counterThread1.start();
counterThread2.start();
}
}
class Counter {
long count = 0;
// Adding a value to count data member:
public synchronized void add (String label, long value) {
System.out.println(label+ " BEFORE add - " + Thread.currentThread().getName() + ": " + this.count);
this.count += value;
System.out.println(label+ " AFTER add - " + Thread.currentThread().getName() + ": " + this.count);
}
public synchronized long getValue() {
return count;
}
}
class CounterThread implements Runnable {
private String label;
protected Counter counter = null;
public CounterThread(String label, Counter aCounter) {
this.label = label;
this.counter = aCounter;
}
public void run() {
for (int i = 0; i < 10; i++) {
counter.add(label, 1);
}
}
}
Related
I am learning multithreading. I have a following code:
public class Intro {
public static void main(String[] args) {
new Intro().doCounter();
}
private int counter = 0;
synchronized void increment() {
counter++;
}
private void doCounter() {
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 1_000_000; i++) {
increment();
}
System.out.println("first: " + counter);
}
});
Thread thread2 = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 1_000_000; i++) {
increment();
}
System.out.println("second: " + counter);
}
});
thread1.start();
thread2.start();
}
}
Output (can differ):
first: 1741739
second: 2000000
The code has two threads. One thread increment the counter million times, while the second wait. Then the second increment it million times as well. I understand why the second thread get 2 million, but didn't get why the first thread get 1741739. Why it isn't 1 million for the first thread? I think it had to stop at 1 million. Thanks for explanation.
As discussed in the comments, you have two problems.
You need to understand that threading execution is not predictable. Each thread gets scheduled for a certain amount of time on a CPU core as decided by the JVM and the OS. How often each thread gets scheduled, and for how long, depends on conditions at runtime. So their work can be interleaved, with no guarantee as to which thread will run when, or finish first/last.
Your code is accessing a resource, a member field variable counter across threads without protection. This is not thread-safe. Due to modern CPU architecture and the Java Memory Model, your two threads might see two different states of that single variable. For example, each of two cores running your two threads might each have a different copy of the variable in its cache.
One solution is to use AtomicInteger as your counter variable rather than int. An AtomicInteger is thread-safe, protecting access to its contained int value. By using AtomicInteger, you no longer need your synchronized increment method.
Here is some example code for that.
An Incrementor class that contains our AtomicInteger variable named count as a member field. The class carries nested class IncrementingTask that is a Runnable with a run method to be executed on background threads, incrementing our count var a million times. The class has a demo method for starting any number of threads, each thread running an instance of IncrementingTask to increment the million times.
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 Incrementor
{
// Member fields.
final private AtomicInteger count = new AtomicInteger( 0 );
public void demo ( )
{
int threadsLimit = 2;
ExecutorService executorService = Executors.newFixedThreadPool( threadsLimit );
for ( int i = 0 ; i < threadsLimit ; i++ )
{
executorService.submit( new IncrementingTask() );
}
executorService.shutdown();
try { executorService.awaitTermination( 1 , TimeUnit.HOURS ); } catch ( InterruptedException e ) { e.printStackTrace(); }
// At this point, the tasks are all done/canceled/failed.
System.out.println( "RESULTS: count is at: " + this.count.get() );
}
// Runnable task.
class IncrementingTask implements Runnable
{
#Override
public void run ( )
{
for ( int i = 0 ; i < 1_000_000 ; i++ )
{
int incrementedCount = count.incrementAndGet();
if ( i % 100_000 == 0 )
{
System.out.println( "Thread # " + Thread.currentThread().getId() + " incremented count to: " + incrementedCount + " at " + Instant.now() );
}
}
System.out.println( "Thread # " + Thread.currentThread().getId() + " is done incrementing. " + Instant.now() );
}
}
}
A class to run this.
package work.basil.threading;
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
Incrementor incrementor = new Incrementor();
incrementor.demo();
}
}
When run.
Thread # 15 incremented count to: 2 at 2021-03-29T00:04:37.099350Z
Thread # 14 incremented count to: 1 at 2021-03-29T00:04:37.099281Z
Thread # 14 incremented count to: 200002 at 2021-03-29T00:04:37.155680Z
Thread # 15 incremented count to: 198267 at 2021-03-29T00:04:37.155659Z
Thread # 15 incremented count to: 387108 at 2021-03-29T00:04:37.165850Z
Thread # 14 incremented count to: 400002 at 2021-03-29T00:04:37.165894Z
Thread # 15 incremented count to: 552150 at 2021-03-29T00:04:37.168378Z
Thread # 14 incremented count to: 631000 at 2021-03-29T00:04:37.169329Z
Thread # 15 incremented count to: 753457 at 2021-03-29T00:04:37.170931Z
Thread # 14 incremented count to: 840455 at 2021-03-29T00:04:37.171943Z
Thread # 15 incremented count to: 942263 at 2021-03-29T00:04:37.173276Z
Thread # 14 incremented count to: 1049089 at 2021-03-29T00:04:37.174559Z
Thread # 15 incremented count to: 1135900 at 2021-03-29T00:04:37.175726Z
Thread # 14 incremented count to: 1240800 at 2021-03-29T00:04:37.177092Z
Thread # 15 incremented count to: 1308191 at 2021-03-29T00:04:37.177678Z
Thread # 15 incremented count to: 1439696 at 2021-03-29T00:04:37.179523Z
Thread # 15 incremented count to: 1595283 at 2021-03-29T00:04:37.180795Z
Thread # 14 incremented count to: 1604140 at 2021-03-29T00:04:37.181720Z
Thread # 14 incremented count to: 1800001 at 2021-03-29T00:04:37.183231Z
Thread # 14 incremented count to: 1900001 at 2021-03-29T00:04:37.184697Z
Thread # 15 is done incrementing. 2021-03-29T00:04:37.182735Z
Thread # 14 is done incrementing. 2021-03-29T00:04:37.188265Z
RESULTS: count is at: 2000000
Notice that every time we run this, we always get to exactly 2,000,000 million total. Also notice that every time you run this, the list of which thread ran when will vary, as will the count at each time the thread reports to us on the console.
Console lies
Notice the counts look crazy. The first two lines report a count of 2 and then 1 rather than one then two. Same with the third and fourth lines, apparently backwards.
Look more closely to examine the microseconds of the timestamps. Those timestamps are not in chronological order.
Lesson learned: The System.out.println calls do not present on the console in chronological order. So never rely on such console output to give you a true picture of what happened when.
Always include a timestamp such as Instant.now() or System.nanoTime(). If you want to see messages in order, collect them in a thread-safe ordered collection such as Collections.synchronizedList( new ArrayList< String >() ).
Alternatively, if you wanted to keep your int variable and synchronized increment method rather than use AtomicInteger you must protect access to the counter variable in a thread-safe manner. Marking the variable as volatile would help. You can search Stack Overflow to learn more on this.
Im trying to create a program whereby users can enter a range of numbers for eg: 1 and then 10, so 1+2+3+4+5+6+7+8+9+10 will be added, but not directly, they can be separated into threads. So user can input the number of threads, for eg: if its 5 threads, thread 1 will perform 1+2, thread 2 performs 3+4 , thread 3 and so on. Each thread will then add together to come up with a total.
I have done the part where the addition works but im not sure how to separate it into the number of user input threads.
You need to somehow keep the index of elements printed to console already, so it could be done by sending a parameter to the run() function which starts from the first element and keeps on to the second thread.
try the following implementation of the code changes:
for (int i=0; i<threadNo; i++)
{
MultithreadingSum object = new
MultithreadingSum(start,end,threadNo,noOfDigits);
object.run(i*(end/threadNo)); //sending a parameter to run()
}
public void run(int time) //time variable to start each time run() is called from current place
{
int total =0;
System.out.println("Thread executed");
for(a = i + time; a <= j/n+time ; a++){
System.out.print(a +" ");
total+=a;
}
System.out.println(getName() + " is "+ total);
}
This simple program has a shared array and 2 threads:
first thread - shows sum of values in the array.
second thread - subtracts 200 from one cell of the array and adds 200 to another cell.
I would expect to see the results: 1500 (sum of the array), 1300 (if the display occurs between the subtraction and the addition).
But for some reason, sometimes 1100 and 1700 appear, which I can't explain...
public class MainClass {
public static void main(String[] args) {
Bank bank = new Bank();
bank.CurrentSum.start();
bank.TransferMoney.start();
}
}
class Bank {
private int[] Accounts = { 100, 200, 300, 400, 500 };
private Random rnd = new Random();
Thread CurrentSum = new Thread("Show sum") {
public void run() {
for (int i = 0; i < 500; i++) {
System.out.println(Accounts[0] + Accounts[1] + Accounts[2]
+ Accounts[3] + Accounts[4]);
}
}
};
Thread TransferMoney = new Thread("Tranfer"){
public void run(){
for(int i=0; i<50000; i++)
{
Accounts[rnd.nextInt(5)]-=200;
Accounts[rnd.nextInt(5)]+=200;
}
}
};
}
You are not updating the values in an atomic or thread safe manner. This means sometimes you see two more -200 than +200 and sometimes you see two more +200 than -200. As you iterate over the values it is possible to see a +200 value but the -200 value is an earlier value and you miss it, but you see another +200 update again missing the -200 change.
It should be possible to see up to 5 x +200 or 5 x -200 in rare cases.
It's happening because the addition of the five values is not atomic, and may be interrupted by the decrement and increment happening in the other thread.
Here's a possible case.
The display thread adds Accounts[0]+Accounts[1]+Accounts[2].
The updating thread decrements Accounts[0] and increments Accounts[3].
The updating thread decrements Accounts[1] and increments Accounts[4].
The display thread continues with its addition, adding Accounts[3] and Accounts[4] to the sum that it had already partially evaluated.
In this case, the sum will be 1900, because you've included two values after they've been incremented.
You should be able to work out cases like this, to give you sums of anything between 700 and 2300.
Perhaps on purpose, you are not doing the addition operation atomically.
That means that this line:
System.out.println(Accounts[0] + Accounts[1] + Accounts[2]
+ Accounts[3] + Accounts[4]);
Will run in multiple steps, any of which can occur during any iteration of the second thread.
1. Get value of Accounts[0] = a
2. Get value of Accounts[1] = b
...So on
The addition then happens after all the values are pulled from the array.
You can imagine that 200 is subtracted from Accounts[0], which is dereferenced by the JRE, then in another loop of the second thread, 200 is removed from Accounts[1], which is subsequently dereferenced by the JRE. This can result in the the output you see.
The Accounts variable is being accessed from more than one thread, one of which modifies its value. In order for the other thread to reliably read the modified values at all it is necessary to use a "memory barrier". Java has a number of ways of providing a memory barrier: synchronized, volatile or one of the Atomic types are the most common.
The Bank class also has some logic which requires the modifications to be made in multiple steps before the Accounts variable is back in a consistent state. The synchronized keyword can also be used to prevent another block of code that is synchronised on the same object from running until the first synchronized block has completed.
This implementation of the Bank class locks all access to the Accounts variable using the mutex lock object of the Bank object that owns the Accounts variable. This ensures that each synchronised block is run in its entirety before the other thread can run its own synchronised block. It also ensures that changes to the Accounts variable are visible to the other thread:
class Bank {
private int[] Accounts = { 100, 200, 300, 400, 500 };
private Random rnd = new Random();
Thread CurrentSum = new Thread("Show sum") {
public void run() {
for (int i = 0; i < 500; i++) {
printAccountsTotal();
}
}
};
Thread TransferMoney = new Thread("Tranfer"){
public void run(){
for(int i=0; i<50000; i++)
{
updateAccounts();
}
}
};
synchronized void printAccountsTotal() {
System.out.println(Accounts[0] + Accounts[1] + Accounts[2]
+ Accounts[3] + Accounts[4]);
}
synchronized void updateAccounts() {
Accounts[rnd.nextInt(5)]-=200;
Accounts[rnd.nextInt(5)]+=200;
}
}
Below is the java program with which i started learning about mutual exclusion.
class MutexVar{
public static int Turn = 1;
}
class CriticalSection{
private static int modelNumber =0;
public static void setModelNumber(int number){
modelNumber = number;
}
public static int getModelNumber(){
return modelNumber;
}
}
public class MutualExclusion{
public static void main(String[] args){
Thread threadObjRef = new Thread(new Runnable(){
public void run(){
int autoVar = 1;
int newModelNumber = -1;
while(true){
/* Non - critical section - start */
System.out.println("\n" + "In run() thread");
/* Non - critical section - end */
while(MutexVar.Turn == 2){
//System.out.println("loop-run"); //infinite loop problem is here
}
/* Critical Section -start */
CriticalSection.setModelNumber(autoVar);
newModelNumber = CriticalSection.getModelNumber();
MutexVar.Turn = 2;
/* Critical Section -end */
/* Non - critical section - start */
System.out.println("run() thread: " + newModelNumber + "\n");
autoVar = autoVar + 2;
/* Non - critical section - end */
}
}
});
threadObjRef.start();
int autoVar = 0;
int newModelNumber = -1;
while(true){
/* Non - critical section - start */
System.out.println("\n" + "In main thread");
/* Non - critical section - end */
while(MutexVar.Turn == 1){
//System.out.println("loop-main"); //infinite loop problem is here
}
/* Critical Section -start */
CriticalSection.setModelNumber(autoVar);
newModelNumber = CriticalSection.getModelNumber();
MutexVar.Turn = 1;
/* Critical Section -end */
/* Non - critical section - start */
System.out.println("main- thread: " + newModelNumber + "\n");
autoVar = autoVar + 2;
/* Non - critical section - end */
}
}
}
My question:
1) Is there a data race between two threads to set MutexVar.Turn?
2) If no, then this program looks good to me, But my program loops infinitely with below output. why infinite loop loop-run or loop-main?
In main thread
In run() thread
run() thread: 1
In run() thread
My observation:
This looks like a Thread scheduling issue. I learnt that java threads are visible to windows OS because they are created internally using CreateThread() api of kernel32.dll and scheduled by OS as 1-1 threading model in windows. java program runs using java jdk 1.6 on windows 7 multi core OS.
Read your code wrong at first. Looks like you have a stale value.
MutexVar.Turns value is never flushed for other threads to see the latest change. If you changed Turn to be declared as volatile or synchronized on some common lock when you read and write to the common variable shared between threads then you'll probably find MutexVar.Turns value to change.
Always synchronize access to shared mutable data. It's not exactly obvious what the JIT/CPU is doing but you are almost certainly running into thread-caching issues by using a non-volatile Turn. Declare MutrexVar as
static class MutexVar {
public static volatile int Turn = 1;
}
Volatile on a keyword says, Each thread that reads this value will have the most up-to-date value and prohibits compiler reorderings.
A bit more detail of compiler re-orderings. The JIT compiler is able to take your code and hoist the read of Turn. For example it can transform
while(MutexVar.Turn == 1){
//System.out.println("loop-main"); //infinite loop problem is here
}
into
if(MutexVar.Turn == 1) {
while(true) {
//System.out.println("loop-main"); //infinite loop problem is here
}
}
This in no way violates Java's compiler contract and can improve performance dramatically. Declaring the field volatile prevents this type or re-ordering.
This question already has answers here:
What is the meaning of the term "thread-safe"?
(17 answers)
Closed 9 years ago.
From Java Concurrency In Practice:
package net.jcip.examples;
import java.util.concurrent.atomic.*;
/**
* NumberRange
* <p/>
* Number range class that does not sufficiently protect its invariants
*
* #author Brian Goetz and Tim Peierls
*/
public class NumberRange {
// INVARIANT: lower <= upper
private final AtomicInteger lower = new AtomicInteger(0);
private final AtomicInteger upper = new AtomicInteger(0);
public void setLower(int i) {
// Warning -- unsafe check-then-act
if (i > upper.get())
throw new IllegalArgumentException("can't set lower to " + i + " > upper");
lower.set(i);
}
public void setUpper(int i) {
// Warning -- unsafe check-then-act
if (i < lower.get())
throw new IllegalArgumentException("can't set upper to " + i + " < lower");
upper.set(i);
}
public boolean isInRange(int i) {
return (i >= lower.get() && i <= upper.get());
}
}
It says “Both setLower and setUpper are check-then-act sequences, but they do not use sufficient locking to make them atomic. If the number range holds (0, 10), and one thread calls setLower(5) while another thread calls setUpper(4), with some unlucky timing both will pass the checks in the setters and both modifications will be applied. The result is that the range now holds (5, 4) an invalid state.”
How could it happen if AtomicIntegers are thread-safe, did I miss some points? And how to fix this?
The involvement of AtomicInteger has nothing to do with the thread safety of your question.
Here is the problem:
if (i > upper.get)
lower.set(i);
steps 1 and 2 may be individually atomic, but together they form a two step, non-atomic, action.
Here is what can happen:
if blammy passes
context switch to another thread.
the other thread calls upper.set(q) such that q < i
context switch back to this thread.
lower is set to i.
each individual step is atomic in nature, but the collection of steps is not atomic.
A java solution for this is:
synchronized(some_object_reference, maybe this)
{
if (i > upper.get)
lower.set(i)
}
Be sure to us the same object reference to synchronize all setting of the upper and lower values.
Lets create an object:
NumberRange nr= new NumberRange();
Thread A:
nr.setLower(-1); //A1
Thread B:
nr.setLower(-3); //B1
nr.setUpper(-2); //B2
Execution order: B1, then A1 and B2 at the same time: If thread B pass the check before A (-3 < -2), and then A pass its check before B sets the value (-1 < 0) , this code won't throw any error because your methods are not atomic. The check is atomic, and the set method too, but together you have 2 atomic steps, not one.