Mutiple Threads: the application doesn't produce same result every time - java

So here I write three simple class to inspect how multiple threads working in java, but they produce different result everytime I run it. Here is the code:
public class Accum {
private static Accum a = new Accum();
private int counter = 0;
private Accum(){}
public static Accum getAccum(){
return a;
}
public void updateCounter(int add){
counter+=add;
}
public int getCount(){
return counter;
}
}//end of class
public class ThreadOne implements Runnable {
Accum a = Accum.getAccum();
public void run() {
for(int x=0; x<98; x++){
//System.out.println("Counter in TWO "+a.getCount());
a.updateCounter(1000);
try{
Thread.sleep(50);
}catch(InterruptedException ex){}
}
System.out.println("one " + a.getCount());
}
}//end of class
public class ThreadTwo implements Runnable{
Accum a = Accum.getAccum();
public void run() {
for(int x=0; x<99; x++){
//System.out.println("counter in Two "+a.getCount());
a.updateCounter(1);
try{
Thread.sleep(50);
}catch(InterruptedException ex){}
}
System.out.println("two "+a.getCount());
}
public class TestThreaad {
public static void main(String[]args){
ThreadOne t1 = new ThreadOne();
ThreadTwo t2 = new ThreadTwo();
Thread one = new Thread(t1);
Thread two = new Thread(t2);
one.start();
two.start();
}
}end of class
So the expected result would be : one 98098, two 98099, but it turns out that the results are just unpredictable, sometimes it would be 78000 or 81000, I don't know..
but if i add some code to print a line of current value of count, the final result would be correct..
I really have no idea what is going wrong, and even add the keyword synchronized in the ThreadOne and ThreadTwo, run() method, the problem is still there...
I've studied the java for 3 months and this is the most elusive problem I've ever confronted...so thanks in advance for anyone could help me to understand the basic point of multiple threading...

Code is not synchronized. As it is unsynchonized different Thread trying to update counter might be at same time which cause this problem.
If you synchonized updateCounter then access of this method will be in proper.
public synchronized void updateCounter(int add){
counter+=add;
}

In your example, the Accum instance is shared between the threads. Your update process is a typical READ, COMPUTE-UPDATE, WRITE operation sequence. Because the resource is shared and not protected, those three operations (from two threads -- making six operations) can be interleaved in many different ways, causing updates to be lost.
Here is an example ordering of the operations (number indicates thread):
READ #1 -> reads 10
COMPUTE-UPDATE #1 -> computes 1010
READ #2 -> reads 10
WRITE #1 -> writes 1010
COMPUTE-UPDATE #2 -> computes 11
WRITE #2 -> writes 11 (earlier update is lost)
So you see, almost any result is possible. As #SubhrajyotiMajumder notes, you can use synchronized to fix it. But if you do that, maybe threads aren't right for your problem; or alternatively, you need another algorithmic process.

Your code is not synchronized properly.
As an alternative to a synchronized method I would suggest using AtomicInteger to store the variable accessed and modified from different threads.

Related

synchronized keyword not making the function synchronized: Java [duplicate]

This question already has answers here:
What does 'synchronized' mean?
(17 answers)
Closed 1 year ago.
I was practicing multithreading in java and wrote the below code
class Printer {
synchronized void printHi(String x) {
System.out.println(x);
}
}
class MyThread extends Thread {
Printer objm;
MyThread(Printer a) {
objm = a;
}
#Override
public void run() {
for (int i = 0; i < 10; i++) {
objm.printHi("MyThread" + i);
}
}
}
class YourThread extends Thread {
Printer objy;
YourThread(Printer a) {
objy = a;
}
#Override
public void run() {
for (int i = 0; i < 10; i++) {
objy.printHi("YourThread" + i);
}
}
}
public class test {
public static void main(String[] args) {
Printer ob = new Printer();
MyThread mt = new MyThread(ob);
YourThread yt = new YourThread(ob);
mt.start();
yt.start();
}
}
Sometimes I gets the output as:
MyThread0
YourThread0
MyThread1
YourThread1
MyThread2
YourThread2
MyThread3
YourThread3
YourThread4
MyThread4
MyThread5
MyThread6
YourThread5
MyThread7
YourThread6
MyThread8
MyThread9
YourThread7
YourThread8
YourThread9
Which is asynchronous. Why is it so even after making the function printHi() as synchronized?
Synchronized means only one thread can be running a block of code marked synchronized on the same lock object (instance of the object for the case of a synchronized method). It does not mean threads will run in order. It is perfectly correct for the two threads to enter those synchronized blocks in any order, and any number of times before the next thread does. What you want is much more difficult and beyond what a simple synchronized block can do.
If you want it to always go Thread A, Thread B, Thread A, Thread B- first I'd question that those two things should actually be separate threads. Wanting things to run sequentially like that is the number one sign you aren't asynchronous and shouldn't be multiple threads. But if they do, you're probably best off with two threads with message handlers, sending messages to each other about when they're allowed to run. Or using semaphores to signal each other. It's hard to give exact advice because the problem here is obviously a trivialized version of something harder, and without the details the right implementation is hard to guess.
You're synchronizing the printHi function call. That means two instances of printHi on the same object won't run at the same time. That's great. It means you'll never get output like
MyThYourThreadread77
(Side note: Java's printing primitives are already somewhat synchronized if I recall correctly, so that shouldn't happen anyway. But for demonstrative purposes, it'll do)
However, your loop is not synchronized. If you want the whole loop to only happen in one thread at a time, remove synchronized from print and write your loop as
synchronized (objm) {
for (int i = 0; i < 10; i++) {
objm.printHi("MyThread" + i);
}
}
(and the same for objy in YourThread)
There's still no guarantee on which one will happen first, but the two loops won't interrupt each other in this case.

Real world example of Memory Consistency Errors in multi-threading?

In the tutorial of java multi-threading, it gives an exmaple of Memory Consistency Errors. But I can not reproduce it. Is there any other method to simulate Memory Consistency Errors?
The example provided in the tutorial:
Suppose a simple int field is defined and initialized:
int counter = 0;
The counter field is shared between two threads, A and B. Suppose thread A increments counter:
counter++;
Then, shortly afterwards, thread B prints out counter:
System.out.println(counter);
If the two statements had been executed in the same thread, it would be safe to assume that the value printed out would be "1". But if the two statements are executed in separate threads, the value printed out might well be "0", because there's no guarantee that thread A's change to counter will be visible to thread B — unless the programmer has established a happens-before relationship between these two statements.
I answered a question a while ago about a bug in Java 5. Why doesn't volatile in java 5+ ensure visibility from another thread?
Given this piece of code:
public class Test {
volatile static private int a;
static private int b;
public static void main(String [] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread() {
#Override
public void run() {
int tt = b; // makes the jvm cache the value of b
while (a==0) {
}
if (b == 0) {
System.out.println("error");
}
}
}.start();
}
b = 1;
a = 1;
}
}
The volatile store of a happens after the normal store of b. So when the thread runs and sees a != 0, because of the rules defined in the JMM, we must see b == 1.
The bug in the JRE allowed the thread to make it to the error line and was subsequently resolved. This definitely would fail if you don't have a defined as volatile.
This might reproduce the problem, at least on my computer, I can reproduce it after some loops.
Suppose you have a Counter class:
class Holder {
boolean flag = false;
long modifyTime = Long.MAX_VALUE;
}
Let thread_A set flag as true, and save the time into
modifyTime.
Let another thread, let's say thread_B, read the Counter's flag. If thread_B still get false even when it is later than modifyTime, then we can say we have reproduced the problem.
Example code
class Holder {
boolean flag = false;
long modifyTime = Long.MAX_VALUE;
}
public class App {
public static void main(String[] args) {
while (!test());
}
private static boolean test() {
final Holder holder = new Holder();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(10);
holder.flag = true;
holder.modifyTime = System.currentTimeMillis();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
long lastCheckStartTime = 0L;
long lastCheckFailTime = 0L;
while (true) {
lastCheckStartTime = System.currentTimeMillis();
if (holder.flag) {
break;
} else {
lastCheckFailTime = System.currentTimeMillis();
System.out.println(lastCheckFailTime);
}
}
if (lastCheckFailTime > holder.modifyTime
&& lastCheckStartTime > holder.modifyTime) {
System.out.println("last check fail time " + lastCheckFailTime);
System.out.println("modify time " + holder.modifyTime);
return true;
} else {
return false;
}
}
}
Result
last check time 1565285999497
modify time 1565285999494
This means thread_B get false from Counter's flag filed at time 1565285999497, even thread_A has set it as true at time 1565285999494(3 milli seconds ealier).
The example used is too bad to demonstrate the memory consistency issue. Making it work will require brittle reasoning and complicated coding. Yet you may not be able to see the results. Multi-threading issues occur due to unlucky timing. If someone wants to increase the chances of observing issue, we need to increase chances of unlucky timing.
Following program achieves it.
public class ConsistencyIssue {
static int counter = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Increment(), "Thread-1");
Thread thread2 = new Thread(new Increment(), "Thread-2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(counter);
}
private static class Increment implements Runnable{
#Override
public void run() {
for(int i = 1; i <= 10000; i++)
counter++;
}
}
}
Execution 1 output: 10963,
Execution 2 output: 14552
Final count should have been 20000, but it is less than that. Reason is count++ is multi step operation,
1. read count
2. increment count
3. store it
two threads may read say count 1 at once, increment it to 2. and write out 2. But if it was a serial execution it should have been 1++ -> 2++ -> 3.
We need a way to make all 3 steps atomic. i.e to be executed by only one thread at a time.
Solution 1: Synchronized
Surround the increment with Synchronized. Since counter is static variable you need to use class level synchronization
#Override
public void run() {
for (int i = 1; i <= 10000; i++)
synchronized (ConsistencyIssue.class) {
counter++;
}
}
Now it outputs: 20000
Solution 2: AtomicInteger
public class ConsistencyIssue {
static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Increment(), "Thread-1");
Thread thread2 = new Thread(new Increment(), "Thread-2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(counter.get());
}
private static class Increment implements Runnable {
#Override
public void run() {
for (int i = 1; i <= 10000; i++)
counter.incrementAndGet();
}
}
}
We can do with semaphores, explicit locking too. but for this simple code AtomicInteger is enough
Sometimes when I try to reproduce some real concurrency problems, I use the debugger.
Make a breakpoint on the print and a breakpoint on the increment and run the whole thing.
Releasing the breakpoints in different sequences gives different results.
Maybe to simple but it worked for me.
Please have another look at how the example is introduced in your source.
The key to avoiding memory consistency errors is understanding the happens-before relationship. This relationship is simply a guarantee that memory writes by one specific statement are visible to another specific statement. To see this, consider the following example.
This example illustrates the fact that multi-threading is not deterministic, in the sense that you get no guarantee about the order in which operations of different threads will be executed, which might result in different observations across several runs. But it does not illustrate a memory consistency error!
To understand what a memory consistency error is, you need to first get an insight about memory consistency. The simplest model of memory consistency has been introduced by Lamport in 1979. Here is the original definition.
The result of any execution is the same as if the operations of all the processes were executed in some sequential order and the operations of each individual process appear in this sequence in the order specified by its program
Now, consider this example multi-threaded program, please have a look at this image from a more recent research paper about sequential consistency. It illustrates what a real memory consistency error might look like.
To finally answer your question, please note the following points:
A memory consistency error always depends on the underlying memory model (A particular programming languages may allow more behaviours for optimization purposes). What's the best memory model is still an open research question.
The example given above gives an example of sequential consistency violation, but there is no guarantee that you can observe it with your favorite programming language, for two reasons: it depends on the programming language exact memory model, and due to undeterminism, you have no way to force a particular incorrect execution.
Memory models are a wide topic. To get more information, you can for example have a look at Torsten Hoefler and Markus Püschel course at ETH Zürich, from which I understood most of these concepts.
Sources
Leslie Lamport. How to Make a Multiprocessor Computer That Correctly Executes Multiprocessor Programs, 1979
Wei-Yu Chen, Arvind Krishnamurthy, Katherine Yelick, Polynomial-Time Algorithms for Enforcing Sequential Consistency in SPMD Programs with Arrays, 2003
Design of Parallel and High-Performance Computing course, ETH Zürich

Race condition while using Atomic Integer

I am learning about java.util.concurrent.atomic package and trying my hands on Atomic Integer. As per my understanding Atomic package helps to write lock-free code as opposed to using synchronized block. So to test my understanding I wrote the following code:
public class Test{
private final AtomicInteger ai;
public void increment() {
int oldVal = ai.get();
while(!ai.compareAndSet(oldVal, oldVal+1)) {
oldVal = ai.get();
}
}
public int incrementModified() {
return ai.incrementAndGet();
}
public int get() {
return ai.get();
}
public static void main(String[] args) {
Test pc = new Test(5);
Runnable r1 = () -> {
pc.increment();
};
Runnable r2 = () -> {
pc.increment();
};
Runnable r3 = () -> {
pc.increment();
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
Thread t3 = new Thread(r3);
t1.start();
t2.start();
t3.start();
System.out.println(pc.get());
}
When I execute the above code I expect the output to be 8 but I am getting output as 7/8. Then I even used the inbuilt incrementAndGet() method and still got the same output after running the program a number of times.
As per my understanding since atomic can be used as an alternative to synchronized block and it makes the increment operations atomic by using CAS(compare and set instruction) I should always get the output as 8.
But since I am getting different outputs I assume there is a race existing and thus the o/p varies between 7/8.
Could someone point out the mistakes I am making in the above code or correct my understanding about atomic classes in Java?
EDIT:
As pointed out in the comments I didn't use join() and thus was getting incorrect result as main thread was requesting the value while some thread may still be in middle of the operation. I added it and after testing it a number of times I can see the expected result.
The line which prints the value executes concurrently to the other 3 threads. If you want to make sure it executes after the 3 threads have run, then you need to join() on those threads.

Multi-threading to print even and odd numbers in java?

I'm a little confused about the difference between threading and multi-threading in Java as far as syntax. I need to write a program to print even numbers 0 to 30 and then odds using threading and another program to do the same thing using multi-threading. I wrote a program that runs and does what it's supposed to but I don't know whether it's threading or multi-threading, or how to go about doing the one it isn't. Here is my program-
public class OddEven extends Thread {
public static void main(String args[]){
Runnable r1 = new Runnable1();
Thread t1 = new Thread(r1);
Runnable r2 = new Runnable2();
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
class Runnable1 implements Runnable{
public void run(){
for(int i=0; i<=30; i+=2) {
System.out.println(i);
}
}
}
class Runnable2 implements Runnable{
public void run(){
for(int i=1; i<=30; i+=2){
System.out.println(i);
}
}
}
Would this program be considered just a single thread?
public class OddEven {
public static void main(String args[]){
for(int i=0; i<=30; i+=2) {
System.out.println(i);
}
for(int i=1; i<=30; i+=2){
System.out.println(i);
}
}
}
Multithreading enables you to do multiple works simultaneously.
For example, if you make a game in which a boy moves forward & goes on firing as well. If you use single threading system, then either a boy could move forward or can fire on his enemy at a time. He cant do the both the works simultaneously.
In your case, when you call t1.start();, then a new thread gets started which will execute your Runnable1's method. Then you called t2.start();, immediately, it will also another thread gets started & your Runnable2's method will gets executed.
Both the method will get executed simultaneously. If you don't use multi threading, then only after finishing the first loop, the next loop will get start.
Multi-threading mainly use in the programs where main thread may process for a long time & you want to use other functions of the program.
Hope this helps!!!!

Thread without sleep

I'm pretty new using Threads and I just did a little program to understand how it works. As a example a did a prime numbers exercise, the program is running perfectly but what I have discovered is that if I don't use sleep(), the order of the numbers change everytime I press run (without changing the code). So why is happening that?
class Prime extends ThreadDemo implements Runnable
{
public void run()
{
for(int i=2;i<=20;i++)
{
if(prime(i))
{
System.out.printf ("Prime No.= %d \n",i);
}
}
}
}
class notPrime extends ThreadDemo implements Runnable
{
int number= 0;
public void run()
{
prime(number);
}
}
class ThreadDemo
{
public boolean prime(int start_value)
{
for(int i=2; i<start_value; i++)
{
if(start_value%i == 0)
{
System.err.printf ("No. Prime = %d \n", start_value);
return false;
}
}
return true;
}
public static void main(String args[])
{
Prime th1 = new Prime();
Thread childOne = new Thread(th1);
childOne.start();
notPrime th2 = new notPrime();
Thread childTwo = new Thread(th2);
childTwo.start();
}
}
This is the result after I pressed run:
This is the result after pressing again run:
The reason this is happening is that threads run in parallel. When you create a bunch of threads, these threads all start doing things at the same time, and it's a race to see which ones finish first. This isn't deterministic, and sometimes the threads will finish in a different order.
The reason sleep could change this is that sleep will give the threads you created first a head start.
There are two reasons why this happens :
Your prime method is not synchronized.
Even if you synchronize the prime method, you are passing different instances of ThreadDemo to your threads. Locks are obtained on objects. If two threads are passed two different objects of ThreadDemo, each thread will lock its own instance of ThreadDemo thus allowing the Threads to run in parallel.
There are a couple of changes you need to make to your code to make sure that the same ThreadDemo is used for both your threads.
class NotPrimeRunnable implements Runnable {
private ThreadDemo threadDemo;
int number = 0;
public NotPrimeRunnable(ThreadDemo threadDemo) {
this.threadDemo = threadDemo;
}
public void run() {
threadDemo.prime(number);
}
}
class PrimeRunnable implements Runnable {
private ThreadDemo threadDemo;
public PrimeRunnable(ThreadDemo threadDemo) {
this.threadDemo = threadDemo;
}
#Override
public void run() {
for (int i = 2; i <= 20; i++) {
if (threadDemo.prime(i)) {
System.out.printf("Prime No.= %d \n", i);
}
}
}
}
class ThreadDemo {
public synchronized boolean prime(int start_value) {
for (int i = 2; i < start_value; i++) {
if (start_value % i == 0) {
System.err.printf("No. Prime = %d \n", start_value);
return false;
}
}
return true;
}
public static void main(String args[]) {
ThreadDemo runnableTask = new ThreadDemo();
PrimeRunnable th1 = new PrimeRunnable(runnableTask);
Thread childOne = new Thread(th1);
childOne.start();
NotPrimeRunnable th2 = new NotPrimeRunnable(runnableTask);
Thread childTwo = new Thread(th2);
childTwo.start();
}
}
This will fix your problem.
Wikipedia defines thread as: "In computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler".
Schedulers are software modules that run in the SO Kernel and manages the processes and threads execution. Schedulers use time-division multiplexing (as in multitasking) algorithms to ensure that all threads and process will be able to execute. One of the scheduler`s characteristics in SOs such as Windows, Mac OS and Linux is that the CPU switches between different software threads. As stated in Wikipedia: "This context switching generally happens frequently enough that the user perceives the threads or tasks as running at the same time."
Based on these considerations, we can explain your software behavior. Non-real time Operating System such as windows and MAC OSx, and many Linux distributions use scheduler algorithms that are non deterministic, so we cant predict the execution order of the threads, then it`s likely every time you execute you are going to get a different result regarding your text output order.
When you use sleep between the threads execution, it seems that the time amount chosen is enough to th1 execute completely before th2 starts. So the output is shown in the correct order.

Categories