Why does this code fall into an infinite loop - java

I am using jdk1.8.
This code runs directly into an infinite loop, but if I add the commented code, it will run normally. I have tried a lot of codes, as long as the operation of locking is involved, it can run normally.
public class StateTest {
public static void main(String[] args) {
State state = new State();
new Thread(new Work(state)).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
state.setStart(true);
System.out.println("the main thread is finished");
}
static class State {
private boolean isStart = false;
public boolean isStart() {
return this.isStart;
}
public void setStart(boolean start) {
this.isStart = start;
}
}
static class Work implements Runnable {
private State state;
public Work(State state) {
this.state = state;
}
#Override
public void run() {
int i = 0;
//endless loop
while (!this.state.isStart()) {
i++;
// if open this code,it will be ok
// synchronized (this) {
//
// }
}
System.out.println(String.format("work start run after %s loops", i));
}
}
}

The problem is that a State instance is not thread-safe. If one thread calls setStart and a second thread calls isStart, then the second thread may not see the value that the first one set1.
You are using setStart on a State instance so that one instance can signal a second one to end the loop. If the second thread doesn't see the state change (because of the above) then the loop won't terminate2.
Solutions:
Change setStart and isStart to be synchronized methods.
Declare the isStart field to be volatile.
Instead of writing your own State class, use a standard java.util.concurrent class to do the synchronization; e.g. CountDownLatch (javadoc).
I recommend that you take the time to study the Oracle Java Tutorial Lesson on concurrency:
The Java™ Tutorials: Lesson: Concurrency
1 - The technical explanation for why this can happen is set out in the "Java Memory Model" section of the Java Language Specification. However, the JLS is NOT written in a way that beginners can understand, and that part is particularly difficult.
2 - In fact, the JLS doesn't say whether the change will be seen or not seen. The actual behavior is liable to depend on a range of factors that are outside of the programmer's control.

It is not guaranteed the isStart value update is visible in the newly created thread.
Since multiple threads access the isStart field, you want to mark it as volatile to assure the updated variable value will be written always in the main memory and not the CPU cache.
static class State {
private volatile boolean isEnd = false;
// getters & setters
}

Related

synchronized keyword in Java threads

I am trying to see how multithreading(particularly with synchronized keyword) works.In this example I want the second thread abc1 to start executing after thread abc. So I've used synchronized keyword in run function.But the output line which says:
Initial balance in this thread is 10000
Initial balance in this thread is 10000
is what concerns me.Because the initial balance should be "-243000" as indicated in output line
Final balance after intial -243000 is 59049000
because the abc1 thread should wait for abc due to synchronized keyword.
Primarily , I want the threads to behave as if I write
abc.start
abc.join()
abc1.start()
abc1.join()
Here is my source code:
class parallel extends Thread{
account a;
public parallel(account a) {
this.a=a;
}
public synchronized void run() {
synchronized(this) {
System.out.println("Initial balance in this thread is "+a.amount);
long duplicate=a.amount;
boolean flag=true;
//System.out.println("Transaction inititated");
for(int i=0;i<10;i++) {
if(flag==true) {
//System.out.println("Deducting "+amount+"Rs from your account");
a.amount-=a.amount*2;
}
else {
//System.out.println("Depositing "+amount+"Rs from your account");
a.amount+=a.amount*2;
}
flag=!flag;
}
System.out.println("Final balance after intial "+duplicate+" is "+a.amount);
syncro.amount=a.amount;
}
}
}
class account{
public account(long rupe) {
amount=rupe;
}
long amount;
}
public class syncro {
static long amount;
public static void main(String[] args) throws InterruptedException{
//for(int i=0;i<10;i++) {
account ramesh=new account(1000);
parallel abc=new parallel(ramesh);
parallel abc1=new parallel(ramesh);
abc.start();
//abc.join();
abc1.start();
//abc1.join();
//}
//awaitTermination();
//Thread.sleep(4000);
boolean ab=true;
long cd=1000;
for(int i=0;i<10;i++) {
if(ab==true) {
//System.out.println("Deducting "+ab+"Rs from your account");
cd-=cd*2;
}
else {
//System.out.println("Depositing "+a+"Rs from your account");
cd+=cd*2;
}
ab=!ab;
}
//System.out.println("Final amount by multithreading is "+);
System.out.println("Final amount after serial order is "+cd);
}
}
You are mixing the creating of your own threads with the use of synchronized. Also, using synchronized(this) within a synchronized method is doing the same thing twice.
Synchronized is NOT about starting threads. It is about allowing only one thread to enter a certain block of code at a time.
Every object you create has a hidden field that you cannot read, but it does exist. It is of type Thread and it is called owner.
The synchronized keyword interacts with this hidden field.
synchronized (object) {
code();
}
means the following:
If object.owner == Thread.currentThread(), then just keep going and increment a counter.
If object.owner == null, then run object.owner = Thread.currentThread(), set that counter to 1, and keep going.
Otherwise (So, object.owner is some other thread), stop, freeze the thread, and wait around until the owner is set to null, and then we can go to option #2 instead.
Once we're in, run code(). When we get to the closing brace, decrement the counter. If it is 0, run object.owner = null.
Furthermore, all the above is done atomically - it is not possible for 2 threads to get into a race condition doing all this stuff. For example, if 2 threads are waiting for owner to become unset again, only one will 'get it', and the other will continue waiting. (Which one gets it? A VM impl is free to choose whatever it wants; you should assume it is arbitrary but unfair. Don't write code that depends on a certain choice, in other words).
A method that is keyworded with synchronized is just syntax sugar for wrapping ALL the code inside it in synchronized(this) for instance methods and synchronized(MyClass.this) for static methods.
Note that synchronized therefore only interacts with other synchronized blocks, and only those blocks for which the object in the parentheses is the exact same obj reference, otherwise none of this does anything. It certainly doesn't start threads! All synchronized does is potentially pause threads.
In your code, you've put ALL the run code in one gigantic synchronized block, synchronizing on your thread instance. As a general rule, when you synchronize on anything, it's public API - other code can synchronize on the same thing and affect you. Just like we don't generally write public fields in java, you should not lock on public things, and this is usually public (as in, code you don't control can hold a reference to you). So don't do that unless you're willing to spec out in your docs how your locking behaviours are set up. Instead, make an internal private final field, call it lock, and use that (private final Object lock = new Object();).

Why the program without 'volatile' works as 'volatile'?

As typed below, the program has a shared var flag without volatile:
public class T {
public static void main(String[] args) {
TT jump = new TT(() -> {
while (true) {
if (TT.flag) {
System.out.println("jump");
break;
}
}
});
jump.start();
new TT(() -> {
TT.flag = true; // P1
LocalDateTime t1 = LocalDateTime.now();
while (true) {
if (Duration.between(t1, LocalDateTime.now()).toMillis() > 100) {
break;
}
}
System.out.println("flag");
}).start();
}
static class TT extends Thread {
public static boolean flag = false;
public TT(Runnable o) {
super(o);
}
}
}
The program always returns normally. So I believe the line of P1 ,where the flag was set to true, updated flag in other threads.
But why? flag is not volatile, why its value was updated immediately? Always!
But why? flag is not volatile, why its value was updated immediately? Always!
You are simply lucky; or unlucky, depending upon your perspective. I tried this on Ideone, and found that it timed out rather than terminating normally.
Remember: not being able to observe a concurrency bug is not the same as an absence of a concurrency bug.
The most sure you can be about code is when you can prove, according to the specification, that there are no bugs. That doesn't mean that the code will then work correctly; it just means that the problems are in the JVM implementation.
In particulary, you can't prove that this code will work correctly, because there is no happens-before relationship between the write to flag in the second thread, and the read in the first thread. Adding volatile creates this guarantee, because a volatile write happens before a volatile read.
That's not to say it will never work without volatile, it's just not guaranteed: a JVM only has to flush a thread's cached values at least as often as the spec requires, but can do it more often, or indeed not cache values at all.

While loops do not terminate when condition is satisfied

To my understanding the following code should terminate normally as the condition stopRunning = true; is met.
However, when I run this program it is printing only Last line of Main(), Start Method ended is never printed as the while loop is never terminated.
public class Test {
private static boolean stopRunning = false;
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
#Override
public void run() {
start();
}
}).start();
Thread.sleep(100);
stopRunning = true;
System.out.println("Last line of Main()");
}
public static void start() {
while (!stopRunning) {
}
System.out.println("Start Method ended.");
}
}
Please help me understand this behavior.
Changing the flag to volatile with
private static volatile boolean stopRunning = false;
will mean that other threads see the change immediately (from main memory instead of a cache), and the code executes as you expect. How volatile relates to Java's memory model is explained further e.g. in this tutorial.
As Mick stated, you should use the volatile keyword to synchronize your variable, so on a change the new value is written directly back to memory and your code will work as expected.
Be aware (also stated in the article Mick linked) that volatile does not guarantee to avoid race conditions, so if two different threads would read your variable, it is not safe that they both read the same value (despite everything is read from memory and on change directly written back)
As stated in previous answers:
Like Mike stated - in run() you should use Test.start() or rename the method. The start you are calling is the thread's start method.
Also as Mick stated, setting stopRunning as volatile should help. The reason it should work is that it will remove the caching of the variable in the thread's memory and will get/set directly from memory.

Will the assignment of value in a Java Boolean object cause re-allocation in memory

I have the following piece of code
Boolean flag = new Boolean(false);
flag = true;
Will the second line (assignment) cause a recreation of the initial object (basically a call to new()) in the JVM? I am asking because I am using a Boolean object to synchronize multiple threads, and I am afraid that if a re-initialization takes places, the waiting threads will not see the change in value.
In my application, there are multiple threads that are given a reference to the previous Boolean object. Only one thread changes the objects value to true, and the rest wait until the object's value becomes true. So, if T1 is the thread that changes the value, its code is like:
synchronized(flag) {
flag = true;
flag.notifyAll();
}
and the rest of the threads (T2) will have code like:
synchronized(flag) {
while(flag == false)
wait();
if(flag == true) {
//do something
}
}
Therefore, the question is that after the assignment of true to flag, will the other threads (T2) still have access to the original object?
Thanks,
Nick
The assignment flag = false is a boxing conversion. It will get compiled as flag=Boolean.valueOf(false) which will end up returning the constant Boolean.FALSE.
So the answer is, it will not create a new object but it will change the variable flag as it assigns an instance distinct from your previous result of new Boolean(false).
It’s not quite clear what you are actually doing but in general, synchronizing on a mutable variable is broken design.
The problem is that you are mixing the value that makes up your condition and the object to synchronize on. The simplest implementation of your updated intention is to use a simple boolean flag and synchronize on the instance that contains the flag:
class WithFlag {
private boolean flag;
public synchronized void setToTrue() {
if(!flag) {
flag=true;
notifyAll();
}
}
public synchronized void waitForTrue() throws InterruptedException {
while(!flag) wait();
}
}
Note that declaring an instance method synchronized is similar to wrap its code with synchronized(this) { … }
If you want to use a boolean to synchronize threads, you should consider using AtomicBoolean, which is specifically designed for this purpose.
The other answers have already explained that when you say flag=false, it is a boxing conversion which will return the constant Boolean.FALSE. One important point that the other answers have covered but not emphasized on is that when you obtain a lock on two Boolean objects that were assigned the same value through a boxing conversion, it is as good as obtaining a lock on one Boolean object.
My answer attempts to give an example to explain this. Consider the following code that creates two threads that obtain a lock on a Boolean.
public class BooleanTest {
public static void main(String[] args) {
BooleanTest test = new BooleanTest();
test.booleanTest();
}
private void booleanTest() {
BooleanLockTester booleanLock1 = new BooleanLockTester();
booleanLock1.setBooleanLock(true);
BooleanLockTester booleanLock2 = new BooleanLockTester();
booleanLock2.setBooleanLock(true);
BooleanLocker booleanLocker1 = new BooleanLocker(booleanLock1);
BooleanLocker booleanLocker2 = new BooleanLocker(booleanLock2);
Thread threadOne = new Thread(booleanLocker1);
Thread threadTwo = new Thread(booleanLocker2);
threadOne.start();
threadTwo.start();
}
private class BooleanLocker implements Runnable {
private BooleanLockTester booleanLockObj;
public BooleanLocker(BooleanLockTester booleanLockObj) {
this.booleanLockObj = booleanLockObj;
}
#Override
public void run() {
booleanLockObj.testLockOnBoolean();
}
}
private class BooleanLockTester {
private Boolean booleanLock = false;
public synchronized void testLockOnBoolean() {
synchronized (booleanLock) {
for (int i = 0; i<1000000000; ++i) {
System.out.println(Thread.currentThread().getName());
}
}
}
public void setBooleanLock(Boolean booleanLock) {
this.booleanLock = booleanLock;
}
}
}
In the above example, the two threads will never be able to enter the for loop together. When you run the program, you will see that the thread that starts first will start printing on the console and only when it is finished, the next thread will start printing to the console.
Let's make a small change in the above code :
Change the following line in the code :
booleanLock2.setBooleanLock(true);
To this :
booleanLock2.setBooleanLock(false);
You will now see that the threads stop behaving and print to the console in a random order. This is because the threads now obtain a lock on two different objects.

How synchronization helps in variable visibility?

public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
According to "Java Concurrency in Practice", it may be possible that it will print 0 as write to ready might be made visible to the reader thread before write to a number or program never terminate at all because it does not use adequate synchronization. It is not guaranteed that values of ready and number written by main thread will be visible to reader thread.
How is it possible? Program will be run sequentially by a thread and it first writes to number and then ready variable. Isn't it? And how can this program could loop forever?
There are no guarantees that by changing a variable in one thread, other threads will see the results of those changes. Technically there is no happens-before relation between them and thus no guarantees (whilst in practice you'll see the changes almost all the time).
That's why the thread may run forever.
Secondly, why sometimes 0 ?
Well the JLS says that
Writes in one thread that are in a data race with reads in another
thread may, for example, appear to occur out of order to those reads.
Which means that your
number = 42;
ready = true;
Can occur in any order. Now it's more likely they'll appear in order, but again there's no guarantees.
You could fix it by changing the variables to be volatile, in which case the writes will always be visible to the readers or by making the code where you mutate state a critical section (see the book). In general I feel using too many volatile variables is a bit of a hack, so you should try and use them sparingly, for things like thread "running" variables.
public class NoVisibility {
private static volatile boolean ready;
private static volatile int number;
private static class ReaderThread extends Thread {
public void run() {
while (!ready)
Thread.yield();
System.out.println(number);
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
If ready is not marked as 'volatile' than the ReaderThread might check its value (as 0).
It later does not check again about ready's value because it assume it has not changed.
The volatile keyword instructs the compiler not to have such assumptions at all and that the variable's value might change under his feet.

Categories

Resources