简体   繁体   English

Java-如何在继续执行之前等待实例完成

[英]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. 在尝试执行其他所有操作之前,我正在尝试等待一段代码返回true。 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 我要等待的SetupWizard

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. 但是,发生的是主线程冻结,但是应该弹出的第二个UI只是一个透明窗口,上面没有任何内容。 What might be the problem? 可能是什么问题? Or is there any other viable approach to "block code until x becomes true"? 还是有其他可行的方法来“直到x变为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. 如果我只是初始化该类,然后立即从第二个类的Initializer方法中调用registerAccount()而不尝试对UI进行任何操作,那么它将起作用。 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. 但是,我并不想立即进入registerAccount(),因为在此之前,用户必须经历一个半长过程才能输入各种数据,之后必须解冻我们的主要对象。 Any ideas? 有任何想法吗?

You are not using wait() correctly, but it could be very useful in doing what you'd like to do. 您没有正确使用wait(),但是在执行您想做的事情中可能很有用。

First, read the javadoc on Object.wait 首先,阅读Object.wait上的javadoc

Then, in your code where you are currently calling 然后,在您当前正在调用的代码中

this.wait()

change this to 更改为

synchronized (setup) {
  setup.wait();
}

In setup, change setComplete to 在设置中,将setComplete更改为

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 . 有两个不同的对象,您调用的notifyAll在WeakReference对象上,而在您等待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. setupWizard类的registerAccount方法中,您需要进行以下更改,以便在与主锁正在等待锁的对象相同的对象上进行通知。

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 . 同一个线程进入等待状态,同一个线程尝试调用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. 如果该线程进入等待状态,则没有线程可以调用notifyAll ,这导致应用程序永远处于挂起状态。 You need to invoke the setupWizard constructor from a separate thread. 您需要从单独的线程调用setupWizard构造函数。

EDIT 2 there are many issues with your code. 编辑2您的代码有很多问题。

  1. You need to have separate thread calling the registerAccount so that notifying thread is different from the waiting thread. 您需要一个单独的线程来调用registerAccount,以便通知线程与等待线程不同。

  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. 您的构造函数当前会调用registerAccount,尝试在锁objct上进行同步,但是在调用构造函数之后,您会从main传递锁对象。

  3. your object on which you wait and on which you invoke notifyall are different objects 您等待的对象和调用notifyall的对象是不同的对象

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. 从发布的代码中我确实无法确定,但是我怀疑您的情况可能是SetupWizard是框架或对话框,而Main中的代码是由EDT执行的,所以当您在Main中等待EDT时,您会冻结GUI和SetupWizard代码无法执行。

I suggest you just use a Modal Dialog for SetupWizard. 我建议您只对SetupWizard使用模式对话框。 It will block Main while SetupWizard is visible. 当SetupWizard可见时,它将阻止Main。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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