Meaningless Drivel is fun!*
The moose likes Threads and Synchronization and the fly likes Communication between threads Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Communication between threads " Watch "Communication between threads " New topic
Author

Communication between threads

Lee Sigauke
Ranch Hand

Joined: May 16, 2012
Posts: 30
Hello, I'm messing around with threads and I'm relatively new to them. I am trying to make a program that spawns a number of threads and what I'm visualising is a thread "tree" like


The way I see it is that the initial thread I make will remain alive and stay that way as its subsequent "children' continue to spawn more threads until they reach level 1 and when level one is reached the thread that is on level one dies and in doing so kills everything that it's connected to.

He're my attempt at doing so. I have also noticed that if I print out umber of threads left (totalThreads) it counts down but ultimately stops counting at 1027 another thing is that if I put my while loop condition to this.totalThreads == 0 it says non-static variable cannot be referenced from a static context but the variable is static already.

Joanne Neal
Rancher

Joined: Aug 05, 2005
Posts: 3429
    
  12
Lee Sigauke wrote: if I print out umber of threads left (totalThreads) it counts down but ultimately stops counting at 1027

Look at line 22. You create a new instance of ThreadTree and pass 10 and 2048 as parameters and then create a new Thread using this instance.
So you have created one thread but set the value of the totalThreads variable to 2048, so it's hardly surprising that your countdown is inaccurate.


Joanne
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4167
    
  21

Lee Sigauke wrote:The way I see it is that the initial thread I make will remain alive and stay that way as its subsequent "children' continue to spawn more threads until they reach level 1 and when level one is reached the thread that is on level one dies and in doing so kills everything that it's connected to.

That isn't really how it works. There really is no relationship between threads once they are started. The thread that starts another 'child' thread does not stay alive until the child thread finishes. It stays alive until it has nothing left to do, regardless of what the state of threads it initiated is. In order to get the behavior you want you would need to build a communication channel that lets the threads at the lower levels tell the threads at a higher level that they are done, then you need to make the higher levels wait for the signal. You don't do any of this, so your top level threads end well before your lower level threads.

He're my attempt at doing so. I have also noticed that if I print out umber of threads left (totalThreads) it counts down but ultimately stops counting at 1027

More on this later...
another thing is that if I put my while loop condition to this.totalThreads == 0 it says non-static variable cannot be referenced from a static context but the variable is static already.

What, exactly, does 'this' mean? If you know the answer to that then the error makes complete sense.


Actually, that comment is totally wrong. That loop means 'keep spinning until totalThreads is not zero.' Since the new ThreadTree instance were the totalThreads count is set to 2048 is executed in the main thread before this while loop, this while loop never waits and will immediately complete and the main thread will end. You can prove it by putting this in the next line:

You will see that code executed after the initial printout from the first ThreadTree constructor, and probably before much else happens (probably as the second output...)

Now down to your counting problem. There are a bunch of things wrong with it. First, the variables you are sharing between threads are not properly protected by synchronization barriers. That means the actual values any one thread will see is not guaranteed - you need to make sure that the get/subtract/assign steps for setting the totalThreads for the next generation of threads is properly synchronized. Also, if you wanted to make sure the count down was printed properly, you would need to put the println statement in the same synchronized block as the decrement operation. So decrementing in the childSpawn() method as you create a new ThreadTree is probably not the correct place to do it (as the value of the totalThreads variable can change an arbitrary number of times between the constructor call and the println statement). It should probably be done in the constructor so it can share a synchronized block with the output. To learn more about how to protect yourself from this, read here: http://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

Next, your equation for the totalThreads is (int)Math.pow(2,level)*2). Why is that? What number do you expect to be the lower bound? Note, it isn't far from the number you posted. Why the extra *2?

In the end, if I don't add the extra *2 to the initial calculations and properly synchronize, I get the count down to 2 so I think there is one more thing wrong with the formula or an assumption somewhere that I am not picking up.


Steve
Lee Sigauke
Ranch Hand

Joined: May 16, 2012
Posts: 30

It stays alive until it has nothing left to do, regardless of what the state of threads it initiated is. In order to get the behavior you want you would need to build a communication channel that lets the threads at the lower levels tell the threads at a higher level that they are done, then you need to make the higher levels wait for the signal. You don't do any of this, so your top level threads end well before your lower level threads.


That's what I thought as well and where I'm coming from is that this state of doing "work" is maintained for as long as the lower threads are still spawning children because this continuous spawn is still regarded at the work of the initial "parent" thread so if A spawns B spawns C spawns D spawns E spawns F (A will stay alive until F is reached where F is when we run out of code so as F runs out of code, E consequently runs out too and it propagates until it reaches A so the whole thing dies)


What, exactly, does 'this' mean? If you know the answer to that then the error makes complete sense.


My understanding of 'this' is that it refers to the current instance of an object which is why I used it that way, my train of thought was that it if I'm mutating any variables then I will be changing those from the initial instance of the object.


Actually, that comment is totally wrong. That loop means 'keep spinning until totalThreads is not zero.' Since the new ThreadTree instance were the totalThreads count is set to 2048 is executed in the main thread before this while loop, this while loop never waits and will immediately complete and the main thread will end. You can prove it by putting this in the next line:


That "spinning" was meant to emulate the waiting phase so when all threads are spawned then it breaks out and finishes and from your other comment I realised that I was thinking of this all wrong by checking the loop at the moment I make an instance of this class.


Next, your equation for the totalThreads is (int)Math.pow(2,level)*2). Why is that? What number do you expect to be the lower bound? Note, it isn't far from the number you posted. Why the extra *2?


My assumption is that since I'm making two more threads per thread, the initial thread will make two threads, each thread spawned from the initial thread will spawn 2^level so I multiplied that by two to get the total number of threads, unless I'm wrong. I did try to remove the *2 and it seems to cut off at 3, sometimes 2, sometimes 5 but never 1 or 0


Thank you for the link.
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4167
    
  21

Lee Sigauke wrote:That's what I thought as well and where I'm coming from is that this state of doing "work" is maintained for as long as the lower threads are still spawning children because this continuous spawn is still regarded at the work of the initial "parent" thread so if A spawns B spawns C spawns D spawns E spawns F (A will stay alive until F is reached where F is when we run out of code so as F runs out of code, E consequently runs out too and it propagates until it reaches A so the whole thing dies)

No, the child spawning is called from the run() method, which is executed from the new (os) thread after the Thread's (object) start() method is called. Once the start() method is called there is no relationship to the parent. The parent creates a new ThreadTree, creates a new Thread object, starts the new os thread, then comes to an end.

My understanding of 'this' is that it refers to the current instance of an object which is why I used it that way, my train of thought was that it if I'm mutating any variables then I will be changing those from the initial instance of the object.

You were calling from a static method. If 'this' refers to an instance, what instance would it refer to from a static method?

Also, if the variables are static (which they are), you should not be changing them 'from an instance' of the class, since they are not linked to an instance of the class - it is misleading and confusing to do so. You should be modifying them from the Class itself: ThreadTree.totalThreads == 0. That way it is clear you are talking about static variables, not instance variables, and you won't confuse yourself (and others) about the necessity of an instance (which there isn't).

My assumption is that since I'm making two more threads per thread, the initial thread will make two threads, each thread spawned from the initial thread will spawn 2^level so I multiplied that by two to get the total number of threads, unless I'm wrong. I did try to remove the *2 and it seems to cut off at 3, sometimes 2, sometimes 5 but never 1 or 0

Right, 2^level already takes into account that each thread spawns 2 new threads (the 2 part of 2^level). So the extra multiplication by 2 is unnecessary. The reason you get a non-deterministic number (between 0 and 5 it looks like) is because of the synchronization problems I mentioned. Properly synchronized I was always getting 2 last night, and the countdown was correct if I extend the synchronization to the print statements. The reason it came to 2 was because the first Thread (level 10) was never taking itself from the pool (decrementing the value), so there was an offset by one. This would bring the count to 1. The reason it never reaches zero is a 'start counting at 0 or 1' thing. We know there should be 1024 threads based on the 2^10 formula, but are those thread ids 1-1024, or 0-1023. The assumption in the initial code is that counting starts at 1, but your while loop expects it to be 0. So you have to reconcile that by subtracting one from the total thread count at start, so everyone is expecting the same count: (2^level)-1.
Lee Sigauke
Ranch Hand

Joined: May 16, 2012
Posts: 30
You were calling from a static method. If 'this' refers to an instance, what instance would it refer to from a static method?


A static method would be a class method thus if I use the keyword this it would be referring to a non existent instance because I have declared the variable as static which makes it a class variable as opposed to an instance variable, correct ?


Right, 2^level already takes into account that each thread spawns 2 new threads (the 2 part of 2^level). So the extra multiplication by 2 is unnecessary. The reason you get a non-deterministic number (between 0 and 5 it looks like) is because of the synchronization problems I mentioned. Properly synchronized I was always getting 2 last night, and the countdown was correct if I extend the synchronization to the print statements. The reason it came to 2 was because the first Thread (level 10) was never taking itself from the pool (decrementing the value), so there was an offset by one. This would bring the count to 1. The reason it never reaches zero is a 'start counting at 0 or 1' thing. We know there should be 1024 threads based on the 2^10 formula, but are those thread ids 1-1024, or 0-1023. The assumption in the initial code is that counting starts at 1, but your while loop expects it to be 0. So you have to reconcile that by subtracting one from the total thread count at start, so everyone is expecting the same count: (2^level)-1.


Looks like I have even more reading to do, I thought this would have been simple and straight forward to do.

Just for interests sake: The reason I am doing this is because I've recently been looking into multicore programming and came across languages like Erlang and GO; both of them boast about how easy and cheap it is to spawn their own versions of threads which they claim are lightweight so I'm trying to see how expensive it is to generate and kill multiple threads in java....
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2273
    
  28

Note that threads are expensive to create in the OS itself. Java's thread just maps to the underlying thread provided by the OS. Erlang, OTH, cheats (in a good way) and doesn't give you access to the underlying thread at the OS level. It maintains a Thread pool that execute Erlang processes. To a programmer it seems that the Erlang processes are executing concurrently, but it doesn't mean that they are all executing on seperate threads.

A fairer comparison between Erlang and Java would be to use Java's thread executor, and compare how fast you can execute Tasks in an executor versus Processes in Erlang. Erlang does make it much easier to write concurrent programs though. You will need to do a lot of hoop jumping to get the kind of flexibility that you can get with Erlang.
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4167
    
  21

I concur with Jayesh. I have done some research into Erlang for purely educational purposes. Although the cost of actually starting OS level threads is one thing, there is also the difficulty of writing good concurrent code that behaves as expected. Erlang seems to make it much easier than Java.
Steve Luke
Bartender

Joined: Jan 28, 2003
Posts: 4167
    
  21

Lee Sigauke wrote:
You were calling from a static method. If 'this' refers to an instance, what instance would it refer to from a static method?


A static method would be a class method thus if I use the keyword this it would be referring to a non existent instance because I have declared the variable as static which makes it a class variable as opposed to an instance variable, correct ?

Correct. And so:
another thing is that if I put my while loop condition to this.totalThreads == 0 it says non-static variable cannot be referenced from a static context but the variable is static already.
The error wasn't about using totalThreads it was about using this.
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2273
    
  28

Steve Luke wrote:I concur with Jayesh. I have done some research into Erlang for purely educational purposes. Although the cost of actually starting OS level threads is one thing, there is also the difficulty of writing good concurrent code that behaves as expected. Erlang seems to make it much easier than Java.


I dreamt up something similar to on my own as a language to write games in. You know how in games, each sprite looks like it's moving in parallel with other sprites. The way you would do it if you did it in core Java is that each sprite would have a state and a step function that changes the sprite to the next state. Then you have a main loop that goes through the sprites and calls step on them. The problem is each sprite becomes like a state machine instead of a simple function. So, what I thought about is making a language where you could write the rules for each sprite in. A thread or a thread pool can execute one rule at a time in all sprites.

So, I was telling this to another co-worker, and he said "That's Erlang" "Erwhat now?" "Erlang.. it;s a language that works just like that" "Shit.. all good ideas are taken!"
Lee Sigauke
Ranch Hand

Joined: May 16, 2012
Posts: 30
Thank you all for you input and I will definitely look into that thread executor.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Communication between threads
 
Similar Threads
Problems with updating the text of a JButton...!!
daemon Vs User Thread
Another thread question
variable problem
Problem is Parallel Processing of Jobs in Java