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

时间:2017-04-03 14:11:23

标签: java multithreading wait

在我继续处理其他所有事情之前,我试图等待一段代码返回true。我有两个类,每个类都有一个实例运行。

Main 我在哪里打开我想等待完成的新对象

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 我想等待

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;
}

正如您所看到的,这只是代码的相关部分。然而,发生的事情是主线程冻结,但应该弹出的第二个UI只是一个没有任何内容的透视窗口。可能是什么问题?或者是否有任何其他可行的方法来阻止代码直到x成为真正的&#34;?

修改

好的,我想我发现了这个问题;如果我只是初始化类,然后立即从第二个类的初始化方法调用registerAccount()而不尝试对UI做任何事情,它的工作原理。但是,我不想立即去注册帐户(),因为在此之前,用户必须经过一个半长的程序来输入各种数据,之后主要的我们必须解冻。有任何想法吗?

3 个答案:

答案 0 :(得分:0)

你没有正确使用wait(),但它可能对你做你想做的事非常有用。

首先,阅读Object.wait上的javadoc

然后,在您当前正在调用的代码中

this.wait()

将此更改为

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

在设置中,将setComplete更改为

public synchronized void setComplete(Boolean variable) {
    this.complete = variable;
    if (variable) {
      this.notifyAll();
    }
}

这是您如何进行高效多线程锁定/等待/同步的基本框架(有很多内置)

答案 1 :(得分:0)

有两个不同的对象,您调用的notifyAll位于WeakReference对象上,等待Main的对象。

registerAccount类的setupWizard方法中,您需要进行如下更改,以便在与主线程等待锁定的对象相同的对象上进行通知。

Object lock =   ((WeakReference)getCallerRef()).get(); // this will be object of Main in case its not null.
if( lock != null){    
   synchronized( lock ) {
     lock.notifyAll();
   }
}

编辑您所拥有的代码中的一个基本问题是您只拥有一个主题。相同的线程进入等待状态,同一线程尝试调用notifyAll。如果此线程进入等待状态,则没有可以调用notifyAll的线程,这会导致应用程序永远处于挂起状态。您需要从单独的线程调用setupWizard构造函数。

编辑2 您的代码存在许多问题。

  1. 您需要让单独的线程调用registerAccount,以便通知线程与等待线程不同。

  2. 您的构造函数当前调用registerAccount,它尝试在锁定对象上进行同步,但是在调用构造函数后从main传递锁定对象。

  3. 您等待的对象以及您调用notifyall的对象是不同的对象

答案 2 :(得分:0)

我真的无法从您发布的代码中确切地说出来,但我怀疑您的情况可能是SetupWizard是Frame或Dialog而Main中的代码是由EDT执行的,所以当你把EDT打开时在Main中等待你冻结GUI并且SetupWizard代码也不能执行。

我建议您只使用SetupWizard的模态对话框。当SetupWizard可见时,它将阻止Main。