While loop strange trouble

I have a int called processedAnchors. At the beginning of my method it is set to the amount of anchors. The program then processes the anchors and decrements the processedAnchors field when they finish. So here is where it gets strange to me. In my main thread I wait on the threads to finish via.

Strangly this code does not work.

[java]
while(true) {

		if (processedAnchors == 0) {

			break;
		}
	}

[/java]

But his code does work properly.

[java]
while(true){

		System.out.println(processedAnchors);

		if (processedAnchors == 0) {

			break;
		}
	}

[/java]

I find this strange, any insight to this problem.

Add a Thread.sleep(1); JVM tends to lock an endless thread. The other one works only from the fact that it has something to do. Also you can write that code as so.

while(processedAnchors != 0); // And it will do the exact thing, only not so aggressive.

1 Like
@Setekh said: Add a Thread.sleep(1); JVM tends to lock an endless thread. The other one works only from the fact that it has something to do. Also you can write that code as so.

while(processedAnchors != 0); // And it will do the exact thing, only not so aggressive.

True and false. The JVM is not locking endless threads… likely you are running afoul of non-thread safe code. On multicore systems when you have code without synchronization or memory barriers then it’s possible for two threads to see different versions of the same variable.

…this is one of the reasons one should not wade into threading lightly. And the reason one should become super familiar with the java.util.concurrent classes. AtomicInteger exists for a reason, for example.

2 Likes

…but the other advice is spot on. A while(true) loop is almost always a sign of bad code.

1 Like

Check if making processedAnchors volatile solves the problem. If yes, then you have hit memory visibility problem, which is something that somebody has to experience at least once - it makes you a better programmer :wink:

As for the real solution, use CountDownLatch.

<cite>@pspeed said:</cite> True and false. The JVM is not locking endless threads... likely you are running afoul of non-thread safe code. On multicore systems when you have code without synchronization or memory barriers then it's possible for two threads to see different versions of the same variable.

…this is one of the reasons one should not wade into threading lightly. And the reason one should become super familiar with the java.util.concurrent classes. AtomicInteger exists for a reason, for example.


cut me some slack it was 7 am for me >.> it was easier to state it like that, tho i learnt smth, thanks.

@Setekh said: cut me some slack it was 7 am for me >.> it was easier to state it like that, tho i learnt smth, thanks.

Sorry. The “treading lightly” part was for OP.

Any time someone mentions bad stuff that the VM “magically” does, I always feel the need to respond, though. :slight_smile:

1 Like

And to elaborate a bit on what the issue is because this is one of the more esoteric parts of threading…

When you have something like:
[java]
public class MyThread extends Thread {
public int someValue;

public void run() {
    while(true) {
        someValue++;
    }
}

}
[/java]

Each thread accessing someValue may have its own cached version of that. So if some other thread is looping looking at that value it may never change from that Thread’s perspective. It largely depends on what else you might be doing.

Java has the concept of a “memory barrier” which forces all cached data to be flushed and refreshed. The “synchronized” keyword causes a memory barrier (on the beginning of the block but not the end). Accessing “volatile” values will also cause a memory barrier. So if that value was:
public volatile int someValue;
…it would also have fixed the issue. But that’s not really a solution unless you already perfectly know what you are doing. The java.util.concurrent classes were created by some really really smart people so that you don’t have to be as smart as they are do to proper threading.

When you used System.out.println() you inadvertently invoked a memory barrier since System.out is internally thread safe and so must invoke a memory barrier in some way.

I can’t stress enough how important it is to rely on the java.util.concurrent classes whenever possible. Years and years of research by people way about threading than we are went into making those. Lots of things have to be considered when writing safe classes like that.

If you really want to blow your mind some time, read some of the earlier writings on “double checked locking” in Java and why it was impossible to do properly. I learned almost every weird threading thing I know from trying to wrap my brain around those papers. (Another interesting topic if you can properly avoid ever using it is “synchronization piggybacking” or “volatile piggybacking”.)

The move to multicore processors really messed with peoples’ threading code that hadn’t fully understood the spec and the implications.

Edit: and when folks say that accessing values outside of proper synchronization is “unsafe”… they don’t just mean because of atomic operations, consistency, and such… they also mean cases like these where you can have completely inconsistent values… even potentially seeing changes out of order and so on.

Yep. Double check locking was fundamentally broken but so many people didn’t believe it.

@zarch said: Yep. Double check locking was fundamentally broken but so many people didn't believe it.

But note that when the spec was changed around the “volatile” keyword then double checked locking can be done in some cases. But you super have to understand the issue and why what you are doing will work. For example, just making an object reference volatile will not do it. Exactly why is more than I won’t to go into right now.

Thank you guys so much for the information :slight_smile:

Hmm, quote doesn’t seem to be working…

And yes, the volatile keyword was added at least partially for that reason. It’s not a keyword I can remember having used in many many years though, these days there are generally much better solutions to the problem if you need volatile.

@zarch said: Hmm, quote doesn't seem to be working...

And yes, the volatile keyword was added at least partially for that reason. It’s not a keyword I can remember having used in many many years though, these days there are generally much better solutions to the problem if you need volatile.

Just a note… the volatile keyword has been in the language longer than it has been useful. They fixed the spec for volatile right around the same time java.util.concurrent was added.