繁体   English   中英

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

[英]Java - How to wait for an instance to finish before proceeding

在尝试执行其他所有操作之前,我正在尝试等待一段代码返回true。 我有两个类,每个类都运行一个实例。

打开我要等待完成的新对象的主要位置

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变为true为止才阻止代码”?

编辑:

好吧,我想我发现了一个问题; 如果我只是初始化该类,然后立即从第二个类的Initializer方法中调用registerAccount()而不尝试对UI进行任何操作,那么它将起作用。 但是,我并不想立即进入registerAccount(),因为在此之前,用户必须经历一个半长过程才能输入各种数据,之后必须解冻我们的主要对象。 有任何想法吗?

您没有正确使用wait(),但是在执行您想做的事情中可能很有用。

首先,阅读Object.wait上的javadoc

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

this.wait()

更改为

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

在设置中,将setComplete更改为

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

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

有两个不同的对象,您调用的notifyAll在WeakReference对象上,而在您等待Main对象时。

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

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

编辑2您的代码有很多问题。

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

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

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

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

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

暂无
暂无

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

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