简体   繁体   中英

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?

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.

  1. You need to have separate thread calling the registerAccount so that notifying thread is different from the waiting thread.

  2. 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.

  3. your object on which you wait and on which you invoke notifyall are different objects

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM