Multithreading JavaFX任务正在等待另一个任务完成
我对Concurrency是个新手,我已经撞了好几次墙了。 代码几乎描述了一切,但只是为了澄清:用户按下按钮,应用程序向数据库发送查询,同时Multithreading JavaFX任务正在等待另一个任务完成,multithreading,javafx,concurrency,Multithreading,Javafx,Concurrency,我对Concurrency是个新手,我已经撞了好几次墙了。 代码几乎描述了一切,但只是为了澄清:用户按下按钮,应用程序向数据库发送查询,同时statusLabel设置为: 非常感谢 200ms 非常 200ms 非常 200ms 查询结果 我已经设法实现了这一点,但现在,我需要在另一个类中使用查询结果(若成功,将打开另一个窗口),但它永远不会这样做。我得出的结论是,它只是在任务完成之前检查结果,所以结果总是错误的,我不知道如何解决这个问题,所以另一个类在任务完成后检查条件 首先,我的授权类 pu
statusLabel
设置为:非常感谢
200ms
非常
200ms
非常
200ms
查询结果
我已经设法实现了这一点,但现在,我需要在另一个类中使用查询结果(若成功,将打开另一个窗口),但它永远不会这样做。我得出的结论是,它只是在任务完成之前检查结果,所以结果总是错误的,我不知道如何解决这个问题,所以另一个类在任务完成后检查条件 首先,我的
授权
类
public class Authorization {
private static String query = "";
private static boolean isValid;
private static Task<Void> task;
public static void verifyLogin(String username, String password) throws SQLException{
Status.get().unbind();
isValid = false;
task = new Task<Void>() {
@Override
protected Void call() throws SQLException {
while(!isCancelled()) {
try {
updateMessage("Weryfikacja.");
Thread.sleep(200);
updateMessage("Weryfikacja..");
Thread.sleep(200);
updateMessage("Weryfikacja...");
Thread.sleep(200);
if(username.equals("") || password.equals("")) {
task.cancel();
updateMessage("Pola nie mogą być puste");
} else {
query = "SELECT login FROM users WHERE login = ?";
Query.execute(query, username);
if(!Query.resultSet.next()) {
task.cancel();
updateMessage("Nie ma takiego użytkownika");
} else {
query = "SELECT password FROM users WHERE login = ?";
Query.execute(query, username);
if(Query.resultSet.next()) {
String passwordValue = Query.resultSet.getString(1);
if(!password.equals(passwordValue)) {
task.cancel();
updateMessage("Podane hasło jest błędne");
} else {
task.cancel();
updateMessage("");
isValid = true;
}
}
}
}
} catch(InterruptedException e) {
if(isCancelled()) {
break;
}
}
}
return null;
}
};
Status.get().bind(task.messageProperty());
new Thread(task).start();
}
public static boolean isValid() {
return isValid;
}
}
编辑#
很抱歉在updateMessage()
中进行了润色 您的verifyLogin()
方法只是在另一个线程中启动验证过程,然后立即退出。isValid
标志将在该线程完成之前不会更改,这将在以后发生很多次。如果您想先执行验证过程,然后再执行其他操作,那么在verifyLogin()
中管理线程是没有意义的
我真的不太明白你的代码应该做什么;您有一个while(…)
循环,据我所知,它只能执行一次(因此是多余的)。您似乎还执行了两个基本相同的SQL查询。(第一个检查是否有具有特定条件的行,如果有,第二个检索该行。为什么不检索该行并检查它是否存在?)
我将对此进行重构,以便validateLogin()
方法根本不处理线程,只返回验证结果(例如,一个状态字符串,但可能还有其他合适的内容)
现在,我将从login()
方法管理线程。这样,您可以使用任务的onSucceeded
处理程序在任务完成时执行代码:
private void login() {
if( SqlConnection.isConnected()) {
Task<String> verifyTask = new Task<String>() {
@Override
protected String call() throws SQLException {
return Authorization.verifyLogin(loginInput.getText(), passwordInput.getText());
}
};
// probably better to use a progress indicator or similar here, but:
Animation animation = new Timeline(
new KeyFrame(Duration.ZERO, e -> Status.get().set("Weryfikacja.")),
new KeyFrame(Duration.millis(200), e -> Status.get().set("Weryfikacja..")),
new KeyFrame(Duration.millis(400), e -> Status.get().set("Weryfikacja...")),
new KeyFrame(Duration.millis(600)));
animation.setCycleCount(Animation.INDEFINITE);
verifyTask.setOnSucceeded(event -> {
animation.stop();
Status.get().set(verifyTask.getValue());
if(Authorization.isValid()) { // or if (verifyTask.getValue().isEmpty())
// go to next menu
}
});
verifyTask.setOnFailed(event -> {
animation.stop();
verifyTask.getException().printStackTrace();
Debug.log(verifyTask.getException().toString());
}
animation.play();
new Thread(verifyTask()).start();
}
}
private void login(){
if(SqlConnection.isConnected()){
任务验证任务=新任务(){
@凌驾
受保护的字符串调用()引发SQLException{
返回Authorization.verifyLogin(loginInput.getText(),passwordInput.getText());
}
};
//在此处使用进度指标或类似指标可能更好,但:
动画=新时间线(
新关键帧(Duration.ZERO,e->Status.get().set(“Weryfikacja”),
新的关键帧(Duration.millis(200),e->Status.get().set(“Weryfikacja..”),
新的关键帧(Duration.millis(400),e->Status.get().set(“Weryfikacja…”)),
新关键帧(持续时间.millis(600));
animation.setCycleCount(animation.unfinite);
verifyTask.setOnSucceeded(事件->{
动画。停止();
Status.get().set(verifyTask.getValue());
if(Authorization.isValid()){//或if(verifyTask.getValue().isEmpty())
//转到下一菜单
}
});
verifyTask.setOnFailed(事件->{
动画。停止();
verifyTask.getException().printStackTrace();
log(verifyTask.getException().toString());
}
动画。播放();
新线程(verifyTask()).start();
}
}
代码的可能重复非常令人困惑。在任务中执行循环时,的目的是什么?看起来您在循环的第一次迭代中,在各种可能的条件下调用了cancel()
,那么为什么要执行循环呢?无论如何,您的verifyLogin()
方法只是在另一个线程中启动验证过程,然后立即退出。isValid
标志在该线程完成之前不会更改,这会在以后发生很多次。如果您想执行验证过程,然后再执行其他操作,那么在verif中管理线程是没有意义的yLogin()
。这确实有效,但我之前确实做到了这一点,没有使用线程。我开始使用它的原因是因为我想获得“等待效果”。有几种情况,例如查询数据库或打开连接,程序会暂时冻结。我想我只需添加“动画”状态之后是点,所以一旦用户单击某个冻结程序的内容,他会看到当前状态,如“连接”。->“连接…”“->“连接…”等,而不是程序冻结。不知道如何使这些“点浮动”而程序正在等待一些data@user9309329如果不使用线程,进程运行时UI将完全无响应(其他控件无法工作,UI无法重新绘制,等等)。这里不是这样。例如,您可以在启动线程之前立即启动动画或显示进度指示器,并在onSucceeded
中停止/删除它。我以前没有线程的方法根本没有进度指示器,一旦我决定添加它们,我意识到我需要线程来实现这一点,但恩,我在这个领域有点迷茫,因为我以前从未使用过它们。因此,基本上,我需要在verifyTask
之前启动另一个任务,按照我的意愿更新我的statusLabel
,并在“verifyTask”完成后停止?@user9309329在其中添加动画代码。不需要使用线程来创建动画。同样,您可以ld只需使用进度指示器,而不是自己编写。
/**
* @return An empty string if the login is valid, or an error message otherwise
*/
public static String verifyLogin(String username, String password) throws SQLException{
isValid = false ;
if(username.equals("") || password.equals("")) {
return "Pola nie mogą być puste";
}
query = "SELECT login, password FROM users WHERE login = ?";
Query.execute(query, username);
if(!Query.resultSet.next()) {
return "Nie ma takiego użytkownika";
}
String passwordValue = Query.resultSet.getString(2);
if(!password.equals(passwordValue)) {
return "Podane hasło jest błędne" ;
}
isValid = true;
return "" ;
}
private void login() {
if( SqlConnection.isConnected()) {
Task<String> verifyTask = new Task<String>() {
@Override
protected String call() throws SQLException {
return Authorization.verifyLogin(loginInput.getText(), passwordInput.getText());
}
};
// probably better to use a progress indicator or similar here, but:
Animation animation = new Timeline(
new KeyFrame(Duration.ZERO, e -> Status.get().set("Weryfikacja.")),
new KeyFrame(Duration.millis(200), e -> Status.get().set("Weryfikacja..")),
new KeyFrame(Duration.millis(400), e -> Status.get().set("Weryfikacja...")),
new KeyFrame(Duration.millis(600)));
animation.setCycleCount(Animation.INDEFINITE);
verifyTask.setOnSucceeded(event -> {
animation.stop();
Status.get().set(verifyTask.getValue());
if(Authorization.isValid()) { // or if (verifyTask.getValue().isEmpty())
// go to next menu
}
});
verifyTask.setOnFailed(event -> {
animation.stop();
verifyTask.getException().printStackTrace();
Debug.log(verifyTask.getException().toString());
}
animation.play();
new Thread(verifyTask()).start();
}
}