Reputation: 568
i'm trying to write some "game engine" for my projects and I'm facing a problem with threads. When I create a Thread (LoadThread) in main flow, it keeps waiting until Run(); in LoadThread ends.
//loading thread
public class LoadThread implements Runnable{
private boolean running = false;
private Thread loader = null;
public LoadThread(/*init data structures*/){
loader = new Thread(this);
}
public void start(){
running = true;
run();
}
synchronized public void run() {
System.out.println(" loading started ");
while(running){
//do some loading, when done, running = false
}
System.out.println(" loading done ");
}
}
//holds data, starts loading
public class SourceGod {
private LoadThread img_loader;
public void startLoading(){
img_loader = new LoadThread(/* some data structures */);
img_loader.start();
}
}
//runs the game
public class Game extends GameThread implements ActionListener{
private SourceGod sources;
public Game(Window full_screen){
sources = new SourceGod(/* some data structures */);
System.out.println("before");
sources.startLoading();
System.out.println("after");
}
}
//own thread to refresh
abstract public class GameThread extends JPanel implements Runnable{
//anything from there is not called before "after"
}
output
before
loading started
//some loaded data report, takes about 2-3s
loading done
after
Any help will be appreciated. ( little more of code http://paste.pocoo.org/show/orCfn9a8yOeEQHiUrgjG/ ) Thanks, Vojtěch
Upvotes: 0
Views: 253
Reputation: 116858
Your problem is that you are creating a Thread
object in your constructor but when you call start()
you are not starting the thread but running the run()
method in the same thread. This looks to be confusion around extending Thread
versus implementing Runnable
.
What I think you should do instead is something like:
// this should be of type Thread not LoadThread
private Thread img_loader;
...
// don't create the loader thread inside of LoadThread
img_loader = new Thread(new LoadThread(/* some data structures */));
img_loader.start();
LoadThread
is the class of type Runnable
that the thread will be executing. With your current code, when it calls:
img_loader.start();
It isn't actually starting a new Thread, it is just calling the LoadThread.start()
method which calls run()
in the same thread:
public void start(){
running = true;
run();
}
Edit:
In looking more closely at your posted code in the link you provided, you are creating your Thread
object inside of the LoadThread
constructor. This is not a good pattern:
public LoadThread(/*init data structures*/) {
// not recommended IMO
loader = new Thread(this);
}
So again, when you are calling LoadThread.start()
you aren't starting the thread but calling run()
in the same thread. I would use the new Thread(new LoadThread())
pattern instead. If you are stuck on wrapping the Thread
inside of LoadThread
then you should change LoadThread.start()
to be:
// this should be removed, you want to call Thread.start() instead
public void start(){
running = true;
// this will start the internal thread which will call run()
loader.start();
}
Btw, if you want to set running
to be false in another thread then it should be marked as volatile
.
Upvotes: 5
Reputation: 38168
You have several problems in the way you use the Runnable interface :
Here is what you should do in your case :
//loading thread
public class LoadThread implements Runnable{
/** Wether or not the thread is running. */
private boolean running = false;
/** Wrapper thread. */
private Thread loader = null;
public LoadThread(/*init data structures*/){
loader = new Thread(this);
}
public void start(){
running = true;
loader.start();
}
@Override
public void run() {
System.out.println(" loading started ");
while(running){
//do some loading, when done, running = false
}
System.out.println(" loading done ");
running = false;
}
}
As you see, If you want a start method, just call the wrapper thread start method.
Also, if you really need to call start, consider not using a runnable but a thread directly :
//loading thread2
public class LoadThread extends Thread{
/** Wether or not the thread is running. */
private boolean running = false;
@Override
public void run() {
running = true;
System.out.println(" loading started ");
while(running){
//do some loading, when done, running = false
}
System.out.println(" loading done ");
running = false;
}
}
That is much simpler.
Upvotes: 0