Java: Stuck in the while loop in the background thread - java

I'm using LibGDX AsyncExecutor and the following function is called in a background thread. 'tasksForTheMainThread' is the static array of Runnable, which executes its not yet executed elements during each call of the update function in the main thread. The function 'createBox' of 'modelBuilder' creates and returns an object of the class 'Model'.
Briefly explaining, this code executes in the second thread and sends a piece of code (function 'run()') to be used in the first thread. After it's sent, the second thread is frozen until the moment the code in "run()" is completed and the Model object is created (or at least it's supposed to be like that).
However, it works as expected only when the while loop (which just waits until the object is created in the main thread) contains the logging bit (Gdx.app.log("TAG","2");). When it's empty, the second thread freezes forever and never reaches 'point A' even after the creation of the Model object.
Why and how logging can influence that? And why isn't the programme working without it?
void secondThreadFunction()
{
Model model = null;
ChunkManager.tasksForTheMainThread.add(new Runnable()
{
#Override
public void run()
{
model = modelBuilder.createBox(size.x, size.y, size.z, GL20.GL_LINES,
new Material(ColorAttribute.createDiffuse(Color.YELLOW)),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal);
}
});
while (model == null)
{
//Gdx.app.log("TAG","2");
}
//point A
}

You cannot modify a local variable that has been captured to an inner class. Since it has been "captured", you will operate on a copy of the value and it will never be non-null, causing the endless loop. Also note that you are busy-waiting in a tight loop. It might be better to use a Future of some kind.
void secondThreadFunction()
{
AtomicReference<Model> model = new AtomicReference<Model>();
ChunkManager.tasksForTheMainThread.add(new Runnable()
{
#Override
public void run()
{
model.set(modelBuilder.createBox(size.x, size.y, size.z, GL20.GL_LINES,
new Material(ColorAttribute.createDiffuse(Color.YELLOW)),
VertexAttributes.Usage.Position | VertexAttributes.Usage.Normal));
}
});
while (model == null)
{
//Gdx.app.log("TAG","2");
}
//point A
}

Related

Java - How to wait for an instance to finish before proceeding

I'm trying to wait for a piece of code to return true before I proceed with everything else. I have two classes, each has one instance running.
Main where I open the new object I want to wait for to complete
setupWizard setup = new setupWizard();
setup.setVisible(true);
setup.setCallerRef(new java.lang.ref.WeakReference(this));
synchronized(this) {
while (setup.isItComplete() == false) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
ArrayList<String> accounts = Functions.fetchAccounts();
SetupWizard i want to wait for
public setupWizard() {
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
//get handlers
JButton helpBtn = (JButton)getContentPane().getComponent(9);
JButton saveBtn = (JButton)getContentPane().getComponent(8);
JTextField userName = (JTextField)getContentPane().getComponent(3);
JTextField serverField = (JTextField)getContentPane().getComponent(1);
JPasswordField passwordField = (JPasswordField)getContentPane().getComponent(5);
JScrollPane scrolly = (JScrollPane)getContentPane().getComponent(7);
JLabel customQLabel = (JLabel)getContentPane().getComponent(6);
scrolly.setVisible(false);
customQLabel.setVisible(false);
//theb change btn positions and action listeners
setBounds(100, 100, 435, 220);
changeHelpButton(helpBtn);
helpBtn.setEnabled(false);
changeSaveButton(saveBtn, userName, serverField, passwordField);
registerAccount("hi", "hi");
}
public void registerAccount(String pass1, String pass2) {
if (pass1.equals(pass2)) {
Functions.addToDatabase("admin", pass2, 1, 1, 1, 1);
}
setComplete(true);
synchronized(getCallerRef()) {
getCallerRef().notifyAll();
}
dispose();
}
private boolean complete = false;
private Object callerRef;
public boolean isItComplete() {
return this.complete;
}
public void setComplete(boolean variable) {
this.complete = variable;
}
public void setCallerRef(Object mycaller) {
this.callerRef = mycaller;
}
public Object getCallerRef() {
return this.callerRef;
}
As you can see this is only the relevant section of the code. However, what happens is the Main thread freezes, but the second UI that should pop up is just a see-through window with nothing on it. What might be the problem? Or is there any other viable approach to "block code until x becomes true"?
Edit:
Ok I think i figured out a problem with this; if i just initialise the class, and then immediately call registerAccount() from the initialiser method of the second class without trying to do anything with the UI, it works. However, I don't immediately want to go to registerAccount(), because before then there is a semi-long procedure the user has to go through to input all sorts of data, after which the main us has to be unfrozen. Any ideas?
I really can't tell for sure from the code you posted, but I suspect your situation might be that the SetupWizard is a Frame or Dialog and the code in Main is executed by EDT, so when you put EDT on wait in Main you are freezing your GUI and SetupWizard code cannot execute neither.
I suggest you just use a Modal Dialog for SetupWizard. It will block Main while SetupWizard is visible.
You are not using wait() correctly, but it could be very useful in doing what you'd like to do.
First, read the javadoc on Object.wait
Then, in your code where you are currently calling
this.wait()
change this to
synchronized (setup) {
setup.wait();
}
In setup, change setComplete to
public synchronized void setComplete(Boolean variable) {
this.complete = variable;
if (variable) {
this.notifyAll();
}
}
This is the basic framework (there's plenty built on top) of how you do efficient multithreaded locking / waiting / synchronizing
There are two different objects, the notifyAll you invoke is on the WeakReference object where as you wait on the object of Main.
In the registerAccount method of setupWizard class you need to do changes as below so that you notify on the same object as the object upon whose lock Main thread is waiting.
Object lock = ((WeakReference)getCallerRef()).get(); // this will be object of Main in case its not null.
if( lock != null){
synchronized( lock ) {
lock.notifyAll();
}
}
Edit One basic issue in the code you have is that you have justthe single thread. Same thread goes in wait and same thread tries to invoke notifyAll. If this thread goes in wait state then there is no thread which can invoke notifyAll , this results in application being in hanged state forever. You need to invoke the setupWizard constructor from a separate thread.
EDIT 2
there are many issues with your code.
You need to have separate thread calling the registerAccount so that notifying thread is different from the waiting thread.
Your constructor invokes currently the registerAccount which tries to synchronize on the lock objct but you pass the lock object from main after contructor is invoked.
your object on which you wait and on which you invoke notifyall are different objects

Having trouble with multiple handlers in Android

So, I have an activity with a handler.
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
matches = LiveAPI.getMatches();
listAdapter.notifyDataSetChanged();
}
LivePage.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Here I get some data and update my list with it. It works.
When I click on an item of my list, this functon is called
private void showLiveMatch(int position) {
Intent i = new Intent(this, LiveMatch.class);
i.putExtra("match", matches.get(position));
startActivity(i);
}
My new activity appears, wich also contains another handler:
private final Runnable m_Runnable = new Runnable()
{
public void run()
{
if(LiveAPI.getStatus() == 1){
match = LiveAPI.getMatch(match.getId());
displayCommentaries();
}
LiveMatch.this.mHandler.postDelayed(m_Runnable, 5000);
}
};
Sometimes this works as I want.
But in some cases it seems like in second activity is still called LiveAPI.getMatches() from the first handler rather than LiveAPI.getMatch(match.getId());
Every function displays a console text, and that's how I figure it out what function is called.
Can someone explain me why?
Once you post either m_Runnable (from LivePage or LiveMatch), it does its stuff and then schedules itself to run in 5 seconds. Basically, each time you start one with a click, it creates an infinite loop. Enough clicks and you will have the logic for each of these running constantly. (That is, unless you have some other code that periodically calls mHandler.removeCallbacks(m_Runnable); that you haven't shown us.) Without knowing more about what you're trying to do, it's hard to recommend how to fix this, but you should somehow avoid creating these kind of infinite loops.
Be aware that all handlers you create on the UI thread simply feed Runnable objects into the (single) MessageQueue for the thread. So there's no such thing as something being called from one handler or another.

Running Threads and Controlling Them

I need help figuring out how to code this problem I am running into.
I'm creating an elevator simulator. I want to run each Elevator object in separate individual threads. I want to control them with my ElevatorController object. I am imagining the Elevator threads sitting in IDLE and then switching to UP or DOWN when the ElevatorController tells it to.
I have created the Elevators and put them into an ArrayList that is stored in the Building object.
What do I do next? My objective is to make elevator1 go to Floor 11. While elevator1 is moving I need to tell elevator2 to go to Floor 14. As elevator2 is moving to Floor 14, I need to tell it to go to Floor 13 first.
I'm unsure how I am supposed to create these threads and still have a reference to the elevator objects in these threads, so I can tell them the new destination.
I'm new to multithreading.
Define each thread as a field in your building so you can access it later. I would do something like:
public class ElevatorThread extends Thread {
public void run() {
while(!this.interrupted()) {
synchronized(this) {
try {
this.wait();
} catch (InterruptedException e) {
return;
}
}
elevatorThreadRunnable.run();
}
}
Runnable elevatorThreadRunnable;
public void setRunnable(Runnable runnable) {
elevatorThreadRunnable = runnable;
synchronized (this) {
this.notify();
}
}
}
If we define the ElevatorThreads as an array it gets even easier. We can simply:
building.elevatorThreads[0].setRunnable(new Runnable() {
public void run() {
...
}
});
Where:
//I belong in the Building constructor!
Thread[] elevatorThreads = {
new ElevatorThread(),
new ElevatorThread(),
new ElevatorThread()
//number of elevators in building
/*
this could be simplified to a method that takes the number of threads as an int
and returns an inflated array, but that is outside the context of this answer
*/
};
If we do this, our Runnable is ran in the elevator thread of your choosing. The thread will also idle like you requested, until a new Runnable is set.
To kill a thread, we call ElevatorThread.interrupt();, this will cause the thread to stop wait()ing if it is, and then break out of our execution loop; killing the thread.

JTextArea text disappears

I'm making a chess program for a project. I'm trying to add a move history box to the side of the board. The move history works fine, and the data is properly sent to the text area, but the text inside the JTextArea disappears while the AI is thinking about his move.
public void aiMove(){
if (!playing){ return; }
paintImmediately(0,0,totalX,totalY);
ai = eve.getMove(chess,wtm,aiOut); //text disappears here
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
writeMove(ai); //updates move history, text reappears here
playing = stillPlaying();
repaint();
}
private void writeMove(Move move){
char c = "abcdefgh".charAt(7-move.fromY);
char h ="abcdefgh".charAt(7-move.toY);
String s = Character.toString(c)+(move.fromX+1)+" - "+Character.toString(h)+(move.toX+1)+" ";
if (!wtm){
String q = chess.getFullMove()+". "+s+" ";
moves.setText(moves.getText()+q);
}
else {
moves.setText(moves.getText()+s+"\n");
}
}
Here's a print screen of what's happening.
http://s13.postimage.org/mh7hltfk7/JText_Area_disappear.png
SOLVED
Thanks to all replies. I changed aiMove() so it creates a thread. Here is what I did.
Attempt #3... swing is still so foreign to me. I didn't want to change writeMove to getMove or I would have to rewrite the human's turn slightly. Since the project is essentially done, I am trying to avoid as much work as possible :)
The GUI is entirely optional anyways, I was just doing it for fun, and to try and learn a bit of swing.
public void aiMove(){
if (!playing){ return; }
if (!aiThread.isAlive()){
aiThread = new Thread(){
public void run(){
ai = eve.getMove(chess,wtm,aiOut);
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
SwingUtilities.invokeLater(new Runnable(){
public void run(){
writeMove(ai);
}
});
repaint();
playing = stillPlaying();
}
};
aiThread.start();
}
}
It also fixed a problem I had before, in that if I were to hold down the 'a' key (force ai move), it would queue up many forced ai moves. Now that doesn't happen.
The problem is your AI thinking is CPU intensive/time consuming, thus it is considered a long running task. You should not do long running tasks on GUI Event Dispatch Thread as this will cause the UI to seem frozen and thus only show updates after the task has finished.
Fortunately there are 2 different approaches you could use:
Use a Swing Worker which as the tutorial states:
The SwingWorker subclass can define a method, done, which is
automatically invoked on the event dispatch thread when the background
task is finished.
SwingWorker implements java.util.concurrent.Future.
This interface allows the background task to provide a return value to
the other thread. Other methods in this interface allow cancellation
of the background task and discovering whether the background task has
finished or been cancelled.
The background task can provide
intermediate results by invoking SwingWorker.publish, causing
SwingWorker.process to be invoked from the event dispatch thread.
The background task can define bound properties. Changes to these
properties trigger events, causing event-handling methods to be
invoked on the event dispatch thread.
Alternatively create separate Thread for AI thinking and wrap setText call in SwingUtilities.invokeLater(...);
Thread t=new Thread(new Runnable() {
#Override
public void run() {
}
});
t.start();
UPDATE
After reading MadProgrammers comment (+1 to it) please remember to create/manipulate your GUI/Swing components on EDT via the SwingUtilities.invokeLater(..) block. You can read more on it here.
UPDATE 2:
That edit is defeating the point, the only call on EDT in SwingUtilitites block should be the setText or atleast only code that manipulates a Swing component i.e
public void aiMove(){
if (!playing){ return; }
if (!aiThread.isAlive()){ //originally initialized by constructor
aiThread = new Thread(){
public void run(){
ai = eve.getMove(chess,wtm,aiOut);
chess.makeMove(ai);
wtm = !wtm;
humanMove = true;
SwingUtilities.invokeLater(new Runnable(){
public void run(){
writeMove(ai);
}
});
repaint();
playing = stillPlaying();
}
};
aiThread.start();
}
}

Waiting for a Runnable to complete before running another Runnable

I have an Android app with a main tab activity, and several activities within the individual tabs. In my main activity's onCreate(), I have a runnable that creates a list, and in the individual activities, I make use of this list.
In the individual activities's onCreate(), I also have Runnables that operate on the list. However, I need these Runnables to only run when the main tab activity's Runnable completes creating the list, otherwise I'd get a null list. I'm trying to find an elegant way of doing this. Right now, in my main activity's Runnable, I'm setting a global boolean variable isDone, and in my individual activity's Runnable, I'm waiting for isDone to be set via a while loop. This works, but probably isn't the best way of doing so.
Any thoughts?
Thanks.
Edit:
I'm trying the following code out, but I'm getting runtime errors:
In my MainActivity's Runnable:
mainRunnable = new Runnable() {
public void run() {
try {
generateList();
synchronized(this) {
listDone = true;
notifyAll();
}
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
}
};
Thread thread = new Thread(null, mainRunnable, "Background");
thread.start();
In my OtherActivity's Runnable:
otherRunnable = new Runnable() {
public void run() {
synchronized(MainActivity.mainRunnable) {
if (!MainActivity.getListDone()) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
}
};
Thread thread = new Thread(null, otherRunnable, "Background");
thread.start();
The mainRunnable seems to run completely, but the otherRunnable seems to cause the app to crash. I get the following error message:
01-10 15:41:25.543: E/WindowManager(7074): Activity com.myapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#40539850 that was originally added here
01-10 15:41:25.543: E/WindowManager(7074): android.view.WindowLeaked: Activity com.myapp.MainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView#40539850 that was originally added here
You can use the wait and notify methods.
To do this, there needs to be some globally accessible object whose lock isn't used by anything else in the program at this point in time. I'm assuming that the list-creating Runnable itself can play this role.
So you could add something like this to the list-creating Runnable class:
private boolean listsDone = false;
boolean getListsDone() {
return listsDone;
}
And something like this to its run() method, immediately after it's done creating the lists:
synchronized (this) {
listsDone = true;
notifyAll();
}
And something like this to the other Runnables' run() methods, at the point where they need to wait:
synchronized (listCreatingRunnableObject) {
if (!listCreatingRunnableObject.getListsDone()) {
try {
listCreatingRunnableObject.wait();
} catch (InterruptedException e) {
// handle it somehow
}
}
}
Update: To clarify, both synchronized blocks need to be synchronized over the same object, and you have to call wait() and notifyAll() on that object. If the object is the Runnable, then it can be implicit for the first one (as in the above code), but if it's the activity, you need to explicitly use the activity object in both cases.
You can use a Queue like this:
public class RunQueue implemements Runnable
{
private List<Runnable> list = new ArrayList<Runnable>();
public void queue(Runnable task)
{
list.add(task);
}
public void run()
{
while(list.size() > 0)
{
Runnable task = list.get(0);
list.remove(0);
task.run();
}
}
}
This allows you to use one thread rather than multiple threads. And you can maintain all your existing "Runnable" objects while simultaneously cleaning up any code they have for waits and joins.
Set up a CountDownLatch with a value of 1 in the main thread, then have the dependent threads wait on it. When the main thread is done, you Count Down the latch to 0 and the waiters will start right up.
An active wait using a while loop is not a good idea at all. The simplest thing would be for the first Runnable to just fire up the rest of them as its last step. If that can't be made to work for some reason, take a look at posting a message to a Handler.
Is there a reason you are using Runnables and not Threads? If you use Threads, you can use the various thread communication primitives which exist for this exact reason (wait() and join() in particular).
I have created a helper method that contains all the boilerplate code for posting a runnable and waiting until it finishes running.
The logic is similar to what #Taymon describes, but the implementation is more general.
Check it out:
https://gist.github.com/Petrakeas/ce745536d8cbae0f0761
Maybe you can refer to Looper in Android. Simply, a thead keep running task from queue in a while loop.

Categories

Resources