Static variable usage while using Fork-Join - java

Problem statement:- //This is a example, Actual array size is very large
suppose there is class A
public class A{
public static int aa[]=new int[5];
public computeaa(){
for(int i=0;i<5;i++)
aa[i] = useaa(i);
}
//this below function can compute aa[i] value
public int useaa(int i){
if(i<=0)
return 1;
if(aa[i]!=0)
return aa[i];
else
return useaa[i-1]+useaa[i-2];
}
}
And RecursiveAction class B
#Override
protected void compute() {
// TODO Auto-generated method stub
A z=new A();
A.computeaa();
}
public static void main(String[] args) {
List<B> tasks =new ArrayList<B>();
for(int i=1; i<=2; i++){
//There is 2 fork will created
B =new B();
tasks.add(B);
B.fork();
}
if (tasks.size() > 0) {
for (B task : tasks) {
task.join();
}
}
}
Doubt?
suppose fork 1 computes static variable aa[2], and suppose when fork 2 going to computes aa[2], can this fork 2 get the value aa[2] which was computed by fork1 or it will compute seperately??
By my understanding fork 2 in some cases easily access fork1's aa, suppose fork 2 wanted to compute aa[3],It can get the value which was already computed by fork 1. But the problem is suppose when fork 1 will try to compute aa[4], for calculating aa[4], it need aa[3], which fork 1 already computed but can it possible if fork 1 try to get aa[3], but by chance it get the access of aa[3] of fork 1 which was not calculate... again it creating a mess.
I am very puzzle by fork join kindly help
There is simple problem, i want to compute some array which is used by same class, but while creating more then one object i want to use the same array which was computed by other object so that my computation time reduced.
How can i copy or get that array to another object, so that this object doesn't need to compute?

suppose fork 1 computes static variable aa[2], and suppose when fork 2 going to computes aa[2], can this fork 2 get the value aa[2]
which was computed by fork1 or it will compute seperately?
Supposing that the two B tasks run in different threads -- over which you elect not to exercise any control -- those two threads are accessing the same element of the same array object without any synchronization. Either thread can read the value written by the other. Moreover, they may read a different value if they access that array element again. The program is not correctly synchronized and therefore there is no guarantee of sequential consistency.
By my understanding fork 2 in some cases easily access fork1's aa, suppose fork 2 wanted to compute aa[3],It can get the value which
was already computed by fork 1. But the problem is suppose when fork 1
will try to compute aa[4], for calculating aa[4], it need aa[3], which
fork 1 already computed but can it possible if fork 1 try to get
aa[3], but by chance it get the access of aa[3] of fork 1 which was
not calculate... again it creating a mess.
Yes, you judge rightly -- both about possible behaviors and about it being a mess.
There is simple problem, i want to compute some array which is used by
same class, but while creating more then one object i want to use the
same array which was computed by other object so that my computation
time reduced. How can i copy or get that array to another object, so
that this object doesn't need to compute?
Under some circumstances, you might have different threads compute disjoint sections of the array in parallel. The computation presented in the question is not amenable to that, however, because of the dependencies between the data. Because no element past index 1 can be computed before the previous 2 have been computed, computation of the elements needs to be serialized, one way or another. You cannot achieve that any faster than by devoting a single thread to the job.
After such a computation is completed, you can share the initialized array among threads, provided that they synchronize with the completion of the computation one way or another. Additional synchronization requirements apply if any of the threads modify the array after the initial computation is complete.
Your particular case is a bit tricky, because few actions with synchronization significance are present. In particular, your array elements are not (and cannot be) final, and you cannot be confident that the threads in which your tasks run are started only when you fork(); if you had the latter then everything the main thread did before would automatically synchronize with the work of the tasks. As it is, you might do something like this:
public class A {
// not static:
public int aa[] = new int[5];
public void computeAa() {
aa[0] = 1;
aa[1] = 1;
for (int i = 2; i < aa.length; i++) {
aa[i] = aa[i - 1] + aa[i - 2];
}
}
public int getAa(int i) {
return (i < 0) ? 1 : aa[i];
}
}
public class B extends RecursiveAction {
private A myA;
public RecursiveAction(A a) {
myA = a;
}
#Override
protected void compute() {
synchronized (myA) {
// ensure that myA's initialization is complete
while (myA.aa[0] == 0) {
// not yet initialized
myA.wait();
}
}
// ... do something with myA (without modifying it) ...
}
public static void main(String[] args) {
A theA = new A();
synchronized(theA) {
// synchronize the initialization of theA, because other threads will
// check it
theA.computeAa();
// wake up any threads waiting on the initialization
theA.notifyAll();
}
List<B> tasks = new ArrayList<B>();
for(int i = 1; i <= 2; i++){
//There is 2 fork will created
B = new B(theA);
tasks.add(B);
B.fork();
}
for (B task : tasks) {
task.join();
}
}
}
Note here that the main thread creates an instance of A and initializes it before forking any tasks. It provides that instance to each B (thus they share it).

Related

Share local variable value between barrier threads in java

I've been working on implementing a custom Cyclic Barrier which adds values passed into the await method and returns the sum to all threads when after notify is called.
The code:
public class Barrier {
private final int parties;
private int partiesArrived = 0;
private volatile int sum = 0;
private volatile int oldSum = 0;
public Barrier(int parties) {
if (parties < 1) throw new IllegalArgumentException("Number of parties has to be 1 or higher.");
this.parties = parties;
}
public int getParties() { return parties; }
public synchronized int waitBarrier(int value) throws InterruptedException {
partiesArrived += 1;
sum += value;
if (partiesArrived != parties) {
wait();
}
else {
oldSum = sum;
sum = 0;
partiesArrived = 0;
notifyAll();
}
return oldSum;
}
public int getNumberWaiting() { return partiesArrived; }
}
This works, but I hear that there is a way to change the values sum and oldSum (or at least oldSum) into local variables of the waitBarrier method. However, after racking my head over it, I don't see a way.
Is it possible and , if yes, how?
However, after racking my head over it, I don't see a way.
Quite so.
Is it possible and , if yes, how?
it is not possible.
For some proof:
Try marking a local var as volatile. It won't work: The compiler doesn't allow it. Why doesn't it? Because volatile is neccessarily a no-op: local vars simply cannot be shared with another thread.
One might think this is 'sharing' a local:
void test() {
int aLocalVar = 10;
Thread t = new Thread(() -> {
System.out.println("Wow, we're sharing it! " + aLocalVar);
});
t.start();
}
But it's some syntax sugar tripping you up there: Actually (and you can confirm this with javap -c -v to show the bytecode that javac makes for this code), a copy of the local var is handed to the block here. This then explains why, in java, the above fails to compile unless the variable you're trying to share is either [A] marked final or [B] could have been so marked without error (this is called 'the variable is effectively final'). Had java allowed you to access non-(effectively) finals like this, and had java used the copy mechanism that is available, that would be incredibly confusing.
Of course, in java, all non-primitives are references. Pointers, in the parlance of some other languages. Thus, you can 'share' (not really, it'll be a copy) a local var and nevertheless get what you want (share state between 2 threads), because whilst you get a copy of the variable, the variable is just a pointer. It's like this: If I have a piece of paper and it is mine, but I can toss it in a photocopier and give you a copy too, we can't, seemingly, share state. Whatever I scratch on my paper won't magically appear on yours; it's not voodoo paper. But, if there is an address to a house on my paper and I copy it and hand you a copy, it feels like we're sharing that: If you walk over to the house and, I dunno, toss a brick through a window, and I walk over later, I can see it.
Many objects in java are immutable (impervious to bricks), and the primitives aren't references. One solution is to use the AtomicX family which are just simplistic wrappers around a primitive or reference, making them mutable:
AtomicInteger v = new AtomicInteger();
Thread t = new Thread(() -> {v.set(10);});
t.start();
t.yield();
System.out.println(t.get());
// prints 10
But no actual sharing of a local happened here. The thread got a -copy- of the reference to a single AtomicInteger instance that lives on the heap, and both threads ended up 'walking over to the house', here.
You can return sum and have the first party clear it:
public synchronized int waitBarrier(int value) throws InterruptedException {
if (partiesArrived == 0) {
sum = 0;
}
partiesArrived++;
sum += value;
if (partiesArrived == parties) {
notifyAll();
} else {
while (partiesArrived < parties) {
wait();
}
}
return sum;
}
Note that the wait condition should always be checked in a loop in case of spurious wakeups. Also, sum doesn't need to be volatile if it's not accessed outside the synchronized block.

Why this Thread code print wrong unpredicted result sometimes? [duplicate]

This question already has answers here:
Java MultiThreading skips loop and gives wrong result [duplicate]
(3 answers)
Closed 1 year ago.
I'm java beginner and it's first time to use thread.
class Counter2 {
private int value = 0;
public void increment() {
value++;
printCounter();
}
public void decrement() {
value--;
printCounter();
}
public void printCounter() {
System.out.println(value);
}
}
class MyThread3 extends Thread {
Counter2 sharedCounter;
public MyThread3(Counter2 c) {
this.sharedCounter = c;
}
public void run() {
int i = 0;
while (i <= 100) {
sharedCounter.increment();
sharedCounter.decrement();
try {
sleep((int) (Math.random() * 2));
} catch (InterruptedException e) {
}
// System.out.println(i);
i++;
}
}
}
public class MyTest {
public static void main(String[] args) {
Thread t1, t2;
Counter2 c = new Counter2();
t1 = new MyThread3(c);
t1.start();
t2 = new MyThread3(c);
t2.start();
}
}
This code has 2 threads and 1 Counter, which is shared between the threads. The threads just repeat plus 1, minus 1 to the counter value. So, if I guess, the result should be 0. Because initial value was 0 and the number of incremented and decremented are the same. But some times the last printing number is not the 0, but -1 or -2 etc. please explain why this is this.
The Answer by Ranwala is correct.
AtomicInteger
An alternative solution I prefer is the use of the Atomic… classes. Specifically here, AtomicInteger. This class is a thread-safe wrapper around an integer.
Change your member field from Counter2 sharedCounter; to AtomicInteger sharedCounter;. Then use the various methods on that class to increment, to decrement, and to interrogate for current value.
You can then discard your Counter2 class entirely.
Executors
Also, you should know that in modern Java, we rarely need to address the Thread class directly. Instead we use the executors framework added to Java 5.
Define your tasks as either a Runnable or Callable. No need to extend from Thread.
See tutorial by Oracle, and search existing posts here on Stack Overflow.
There are two issues here. They are atomicity and visibility aspects of concurrency. Both increment and decrement are compound actions and need to be atomically performed in a multi-threaded environment. Apart from that you should not read a stale value whenever you read the counter. None of these are guaranteed by your current implementation.
Coming back to the solution, one naive way of achieving this is by using synchronized methods which uses a lock on the current instance to achieve the thread-safety. But that comes at a fairly high cost and incurs more lock overhead.
A much better approach would be to use CAS based non-blocking synchronization to achieve the task at hand. Here's how it looks in practice.
class Counter2 {
private LongAdder value = new LongAdder();
public void increment() {
value.increment();;
printCounter();
}
public void decrement() {
value.decrement();;
printCounter();
}
public void printCounter() {
System.out.println(value.intValue());
}
}
Since you are a beginner, I would recommend you to read the great book Java Concurrency in Practice 1st Edition which explains all these basics in a very nice, graspable manner by some of the great authors in our era ! If you have any questions about the contents of the book, you are welcome to post the questions here too. Read it from cover to cover at least twice !
Update
CAS is so called ComparaAndSwap is a lock free synchronization scheme achieved by using low level CPU instructions. Here it reads the value of the counter before the increment/decrement and then at the time it is updated, it checks whether the initial value is still there. If so, it updates the value successfully. Otherwise, chances are that another thread concurrently updating the value of the counter, hence the increment/decrement operation fails and it retries it again.

Java ArrayList thread unsafe example explanation

class ThreadUnsafe {
static final int THREAD_NUMBER = 2;
static final int LOOP_NUMBER = 200;
public static void main(String[] args) {
ThreadUnsafe test = new ThreadUnsafe();
for (int i = 0; i < THREAD_NUMBER; i++) {
new Thread(() -> {
test.method1(LOOP_NUMBER);
}, "Thread" + i).start();
}
}
ArrayList<String> list = new ArrayList<>();
public void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2();
method3();
}
}
private void method2() {
list.add("1");
}
private void method3() {
list.remove(0);
}
}
The code above throws
java.lang.IndexOutOfBoundsException: Index: 0, Size: 1
I know ArrayList is not thread-safe, but in the example, I think every remove() call is guaranteed to be preceded by at least one add() call, so the code should be OK even the order is messed up like the following:
thread0: method2()
thread1: method2()
thread1: method3()
thread0: method3()
Some explanations needed here, please.
If always one add() or remove() call is completely finished before another one is started, your reasoning is correct. But ArrayList doesn't guarantee that as its methods aren't synchronized. So, it can happen that two threads are in the middle of some modifying calls at the same time.
Let's look at the internals of e.g. the add() method to understand one possible failure mode.
When adding an element, ArrayList increases the size using size++. And this is not atomic.
Now imagine the list being empty, and two threads A and B adding an element at exactly the same moment, doing the size++ in parallel (maybe in different CPU cores). Let's imagine things happen in the following order:
A reads size as 0.
B reads size as 0.
A adds one to its value, giving 1.
B adds one to its value, giving 1.
A writes its new value back into the size field, resulting in size=1.
B writes its new value back into the size field, resulting in size=1.
Although we had 2 add() calls, the size is only 1. If now you try to remove 2 elements (and this time it happens sequentially), the second remove() will fail.
To achieve thread safety, no other thread should be able to mess around with the internals like size (or the elements array) while one access is currently in progress.
Multi-threading is inherently complex in that the calls from multiple threads can not only happen in any (expected or unexpected) order, but that they can also overlap, unless protected by some mechanism like synchronized. On the other hand, excessive use of the synchronization can easily lead to poor multi-thread performance, and also to dead-locks.
As a supplement to #RalfKleberhoff's answer,
I think every remove() call is guaranteed to be preceded by at least one add() call,
Yes.
so the code should be OK even the order is messed up
No, that is not a valid inference with respect to a multithreaded program.
Your program contains data races as a result of two threads both accessing the same shared, non-atomic object, with some of those accesses being writes, without appropriate synchronization. The whole behavior of a program that contains data races is undefined, so in fact you cannot draw any conclusions at all about its behavior.
Do not try to cheat or scrimp on synchronization. Do minimize the amount of it that you need by limiting your use of shared objects, but where you need it, you need it, and the rules for determining when and where you need it are not that hard to learn.
ArrayList in java docs says,
Note that this implementation is not synchronized. If multiple threads
access an ArrayList instance concurrently, and at least one of the
threads modifies the list structurally, it must be synchronized
externally.
Why this code is not thread safe ?
Multiple thread running on Machine runs independent of each other.
public void method1(int loopNumber) {
for (int i = 0; i < loopNumber; i++) {
method2();
method3();
}
}
Here method2() and method3() are being process sequential within
the thread but not across the thread. ArrayList list is common between both thread. which will be in inconstant state between both thread on multi core system.
Interesting test would be add empty check in method3() and set LOOP_NUMBER = 10000;
private void method3()
{
if (!list.isEmpty())
list.remove(0);
}
In result you should get same Runtime Exception some thing like java.lang.IndexOutOfBoundsException: Index: 0, Size: 1 or java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 because of same reason inconstant state of variable in list i.e. size.
To fix this issue you could have added synchronized like below or use Syncronized list
public void method1(int loopNumber)
{
for (int i = 0; i < loopNumber; i++)
{
synchronized (list)
{
method2();
method3();
}
}
}

Java Thread safety - Understanding the need of synchronization

I am having a very hard time trying to understand the concept of synchronizing methods, objects and understand the main issue of not doing so, when running a multi-threaded application.
I understand that synchronize keyword is used to make sure that only one thread will work with a specific object or enter a specific block or method in a time, basically locks it and unlocks when the execution ended, so the other threads can enter it.
But I don't really understand the problem, I am totally confused, I created a demo application, where I have 2 bank accounts, and one bank class which has 5000 funds and a method that transfers a specific amount of money to the given account, and in it's constructor it creates the 2 bank accounts and start the threads (each account is a thread).
Now in the bank account's class I have a funds field, and a run method which the thread will call upon start (the class inheriting Thread), and the run method will loop 10 times, and take 20 dollar from the main bank by calling Bank#takeFunds(int amount)
So there we go, the Bank class:
public class Bank {
private int bankmoney = 5000;
public Bank() {
Client a = new Client(this);
Client b = new Client(this);
a.start();
b.start();
}
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
bankmoney -= amount;
c.addFunds(amount);
}
}
public void print() {
System.out.println("left: " + bankmoney);
}
public static void main(String... args) {
new Bank();
}
}
And the Client class:
public class Client extends Thread {
private Bank b;
private int funds;
Random r = new Random();
public Client(Bank b) {
this.b = b;
}
public void addFunds(int funds) {
this.funds += funds;
}
public void run() {
for (int i = 0; i < 10; i++) {
b.takeMoney(this, 20);
}
System.out.println(Thread.currentThread().getName() + " : " + funds);
b.print();
}
}
And the output for me:
Thread-0 : 200
left: 4800
Thread-1 : 200
left: 4600
The program ends with 200$ in each account, and 4600 left in the bank, so I don't really see the issue, I am failing to demonstrate the issue of thread safety, and I think this is why I can't understand it.
I am trying to get the most simple explanation on how it works exactly, How can my code turn into a problem with thread safety?
Thanks!
Example:
static void transfer(Client c, Client c1, int amount) {
c.addFunds(-amount);
c1.addFunds(amount);
}
public static void main(String... args) {
final Client[] clients = new Client[]{new Client(), new Client()};
ExecutorService s = Executors.newFixedThreadPool(15);
for (int i = 0; i < 15; i++) {
s.submit(new Runnable() {
#Override
public void run() {
transfer(clients[0], clients[1], 200);
}
});
}
s.shutdown();
while(!s.isTerminated()) {
Thread.yield();
}
for (Client c : clients) {
c.printFunds();
}
}
Prints:
My funds: 2000
My funds: 8000
To start with, a thread is not an object. Do not assign a separate thread to each client. Threads do work and objects contain code which specifies what must be done.
When you call methods on a Client object, they do not execute "on that client's thread"; they execute in the thread from which they are called.
In order to make a thread do some work, you need to hand it over an object implementing the code to be executed on it. That's what an ExecutorService allows you to do simply.
Also keep in mind that locks do not "lock objects" and synchronized(anObject) will not on its own stop another thread from calling anObject's methods at the same time. Locks only prevent other threads trying to acquire the same lock from proceeding until the first thread is done with it.
I tested your program, and in fact got the following output:
(The result is not 4600 as in your case.)
The point is that just because it happens to work once doesn't mean that it will always work. Multi threading can (in an illsynchronized program) introduce non-determinism.
Imagine what would happen if your operations took a bit longer to execute. Let's simulate this with a Thread.sleep:
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
bankmoney -= amount;
c.addFunds(amount);
}
}
Now try running your program again.
your program is working fine , as you are only deducting total amount of 2000. Which is far lesser than initial value. So, this check has no play, you code will work even if you rmeove it.
if (bankmoney >= amount) {
The only bad thing that can happen in this scenario , if client1 checks that amount is more than he needs to withdraw , but in meantime other client withdraws it.
public void run() {
for (int i = 0; i < 100; i++) {
b.takeMoney(this, 200);
}
System.out.println(Thread.currentThread().getName() + " : " + funds);
b.print();
}
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
system.println("it is safer to withdraw as i have sufficient balance")
bankmoney -= amount;
c.addFunds(amount);
}
}
there will be time when client one will check bankmoney is greater than amount , but when he withdraws, it will reach to negative amount. as other thread will take that amount.
Run program, 4-5 times you will realize.
Let's look at a more realistic example and implement a transfer function for our Bank:
public boolean transfer(long amount, Client source, Client recipient) {
if(!source.mayTransferAmount(amount)) return false; // left as an exercise
source.balance -= amount;
recipient.balance += amount;
}
Now let's imagine two threads. Thread A transfers a single unit from Client x to Client y while Thread B transfers a single unit from Client y to Client x. Now you must know that without synchronization, you cannot be sure how the CPU orders operations, so it could be:
A: get x.balance (=100) to tmpXBalance
B: get x.balance (=100) to tmpXBalance
B: increment tmpXBalance (=101)
B: store tmpXBalance to x.balance (=101)
A: decrement tmpXBalance (=99)
A: store tmpXBalance to x.balance (=99)
(rest of exchange omitted for brevity)
Whoa! We just lost money! Client x won't be very happy. Note that locking alone won't give you any guarantee, you also need to declare balance as volatile.
Any time there's something you want to do to data that are shared by more than one thread, if it takes more than one step, then you probably need synchronization.
This takes three steps:
i++;
The steps are; (1) get the value of i from memory into a register, (2) add 1 to the register, (3) store the value of the register back into memory.
A running thread can be preempted at any time. That means, the operating system can pause it, and give some other thread a turn using the CPU. So, if there's no synchronization, thread A could perform step (1) of incrementing i (it could get the value into a register), and then it could be preempted. While thread A is waiting to run again, threads B, C, and D could each increment i a thousand times. Then when thread A finally got to run again, it would add 1 to the value that it originally read, and then store that back into memory. The three thousand increments by threads B, C, and D would be lost.
You need synchronization whenever one thread could put some data into a temporary state that you don't want other threads to see or operate on. The code that creates the temporary state must be synchronized, and any other code that could operate on the same data must be synchronized, and any code that merely allows a thread to see the state must synchronized.
As Marko Topolnik pointed out, synchronization doesn't operate on data, and it doesn't operate on methods. You need to make sure that all of the code that modifies or looks at a particular collection of data is synchronized on the same object. That's because synchronization does one thing, and one thing only:
The JVM will not allow two threads to be synchronized on the same object at the same time. That's all it does. How you use that is up to you.
If your data are in a container, it may be convenient for you to synchronize on the container object.
If your data are all instance variables of the same Foobar instance, then it may be convenient for you to synchronize on the instance.
If your data are all static, then you probably should synchronize on some static object.
Good luck, and have fun.

Multi-threading program to print numbers from 1 to 50?

im trying to write a program in which two threads are created and the output should be like 1st thread prints 1 and the next thread prints 2 ,1st thread again prints 3 and so on. im a beginner so pls help me clearly. i thought thread share the same memory so they will share the i variable and print accordingly. but in output i get like thread1: 1, thread2 : 1, thread1: 2, thread2 : 2 nd so on. pls help. here is my code
class me extends Thread
{
public int name,i;
public void run()
{
for(i=1;i<=50;i++)
{
System.out.println("Thread" + name + " : " + i);
try
{
sleep(1000);
}
catch(Exception e)
{
System.out.println("some problem");
}
}
}
}
public class he
{
public static void main(String[] args)
{
me a=new me();
me b=new me();
a.name=1;
b.name=2;
a.start();
b.start();
}
}
First off you should read this http://www.oracle.com/technetwork/java/codeconventions-135099.html.
Secondly the class member variables are not shared memory. You need to explicitly pass an object (such as the counter) to both objects, such that it becomes shared. However, this will still not be enough. The shared memory can be cached by the threads so you will have race-conditions. To solve this you will need to use a Lock or use an AtomicInteger
It seems what you want to do is:
Write all numbers from 1 to 50 to System.out
without any number being printed multiple times
with the numbers being printed in order
Have this execution be done by two concurrent threads
First, let's look at what is happening in your code: Each number is printed twice. The reason for this is that i is an instance variable of me, your Thread. So each Thread has its own i, i.e., they do not share the value.
To make the two threads share the same value, we need to pass the same value when constructing me. Now, doing so with the primitive int won't help us much, because by passing an int we are not passing a reference, hence the two threads will still work on independent memory locations.
Let us define a new class, Value which holds the integer for us: (Edit: The same could also be achieved by passing an array int[], which also holds the reference to the memory location of its content)
class Value{
int i = 1;
}
Now, main can instantiate one object of type Value and pass the reference to it to both threads. This way, they can access the same memory location.
class Me extends Thread {
final Value v;
public Me(Value v){
this.v = v;
}
public void run(){
for(; v.i < 50; v.i++){
// ...
}
public static void main(){
Value valueInstance = new Value();
Me a = new Me(valueInstance);
Me b = new Me(valueInstance);
}
}
Now i isn't printed twice each time. However, you'll notice that the behavior is still not as desired. This is because the operations are interleaved: a may read i, let's say, the value is 5. Next, b increments the value of i, and stores the new value. i is now 6. However, a did still read the old value, 5, and will print 5 again, even though b just printed 5.
To solve this, we must lock the instance v, i.e., the object of type Value. Java provides the keyword synchronized, which will hold a lock during the execution of all code inside the synchronized block. However, if you simply put synchronize in your method, you still won't get what you desire. Assuming you write:
public void run(){ synchronized(v) {
for(; v.i < 50; v.i++) {
// ...
}}
Your first thread will acquire the lock, but never release it until the entire loop has been executed (which is when i has the value 50). Hence, you must release the lock somehow when it is safe to do so. Well... the only code in your run method that does not depend on i (and hence does not need to be locking) is sleep, which luckily also is where the thread spends the most time in.
Since everything is in the loop body, a simple synchronized block won't do. We can use Semaphore to acquire a lock. So, we create a Semaphore instance in the main method, and, similar to v, pass it to both threads. We can then acquire and release the lock on the Semaphore to let both threads have the chance to get the resource, while guaranteeing safety.
Here's the code that will do the trick:
public class Me extends Thread {
public int name;
final Value v;
final Semaphore lock;
public Me(Value v, Semaphore lock) {
this.v = v;
this.lock = lock;
}
public void run() {
try {
lock.acquire();
while (v.i <= 50) {
System.out.println("Thread" + name + " : " + v.i);
v.i++;
lock.release();
sleep(100);
lock.acquire();
}
lock.release();
} catch (Exception e) {
System.out.println("some problem");
}
}
public static void main(String[] args) {
Value v = new Value();
Semaphore lock = new Semaphore(1);
Me a = new Me(v, lock);
Me b = new Me(v, lock);
a.name = 1;
b.name = 2;
a.start();
b.start();
}
static class Value {
int i = 1;
}
}
Note: Since we are acquiring the lock at the end of the loop, we must also release it after the loop, or the resource will never be freed. Also, I changed the for-loop to a while loop, because we need to update i before releasing the lock for the first time, or the other thread can again read the same value.
Check the below link for the solution. Using multiple threads we can print the numbers in ascending order
http://cooltekhie.blogspot.in/2017/06/#987628206008590221

Categories

Resources