基本上,我在远程数据库上进行了一些SQL查询,并且我被告知要始终在单独的线程中运行查询,以免打扰主应用程序的循环(考虑到它'实时游戏)。我刚刚开始添加SQL支持而不是在单独的线程上运行查询会导致大量延迟;这就是我试图做的事情:
public boolean login(final String username, final String password) {
final AtomicBoolean value = new AtomicBoolean(false);
Thread thread = new Thread(new Runnable() {
public void run() {
Connection connection = null;
Statement statement = null;
ResultSet results = null;
try {
connection = getConnection("root", "", "localhost");
statement = connection.createStatement();
results = statement.executeQuery("SELECT * from `db`.`accounts` WHERE `username`='"+username+"'");
while(results.next()) {
String salt = results.getString("salt");
String dbPass = results.getString("password");
String hashPass = toMD5(toMD5(salt) + toMD5(password));
if(hashPass.equals(dbPass)) {
value.set(true);
}
}
} catch(SQLException e) {
e.printStackTrace();
}
}
});
thread.start();
return value.get();
}
然而,问题是在返回应用程序之前永远不会设置原子布尔值。我试图找到最好的方法来做到这一点,而不会阻止我呼吁的线程。
注意:我知道我应该在这里使用预备语句,试图先弄清楚这一点。
答案 0 :(得分:1)
我正在尝试找到最佳方法,而不会阻止我正在调用的线程。
这是不可能的。如果该线程需要结果,则必须阻塞,直到该结果可用。
一种选择是使用CompletableFuture<Boolean>
。
CompletableFuture<Boolean> future = new CompletableFuture<>();
Thread thread = new Thread(new Runnable() {
public void run() {
...
// when ready, successful (maybe false otherwise)
future.complete(true)
...
}
});
然后你可以调用阻塞当前线程的future.get()
,也可以注册一个监听器,该监听器将在设置结果时被调用(在该另一个线程中,或者如果结果已经准备就在当前线程中) )。
使用线程池而不是管理自己的线程。
答案 1 :(得分:0)
我试图找到最好的方法来做到这一点,而不会阻止我呼吁的线程。
你需要的是一个监听器,它可以监听你的线程完成然后执行你的代码。
假设您要从线程返回ResultSet。首先,您创建自己的EventObject。
package com.ggl.event.listener;
import java.sql.ResultSet;
import java.util.EventObject;
public class ResultSetEventObject extends EventObject {
private static final long serialVersionUID = 6904165475135245131L;
private ResultSet resultSet;
public ResultSetEventObject(Object source) {
super(source);
}
public ResultSet getResultSet() {
return resultSet;
}
public void setResultSet(ResultSet resultSet) {
this.resultSet = resultSet;
}
}
除了扩展EventObject之外,这个类没有什么特别之处。您的构造函数由EventObject定义,但您可以创建所需的任何方法。
其次,定义一个EventListener接口。
package com.ggl.event.listener;
public interface EventListener {
public void handleEvent(ResultSetEventObject eo);
}
您将使用您创建的EventObject。您可以使用所需的任何方法名称。这是代码的接口,将作为对侦听器的响应而写入。
第三,你写了一个ListenerHandler。
package com.ggl.event.listener;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class ResultSetListenerHandler {
protected List<EventListener> listeners;
public ResultSetListenerHandler() {
listeners = new ArrayList<EventListener>();
}
// Add method(s) to generate a ResultSet and perform the
// fireEvent method.
public void addListener(EventListener listener) {
listeners.add(listener);
}
public void removeListener(EventListener listener) {
for (int i = listeners.size() - 1; i >= 0; i--) {
EventListener instance = listeners.get(i);
if (instance.equals(listener)) {
listeners.remove(i);
}
}
}
public void fireEvent(final ResultSetEventObject eo,
final ResultSet resultSet) {
for (int i = 0; i < listeners.size(); i++) {
final EventListener instance = listeners.get(i);
Runnable runnable = new Runnable() {
public void run() {
eo.setResultSet(resultSet);
instance.handleEvent(eo);
}
};
new Thread(runnable).start();
}
}
}
这就是你编写事件监听器的方式。在你的代码中,你会写这样的东西:
ResultSetListenerHandler handler = new ResultSetListenerHandler();
handler.addListener(new EventListener() {
@Override
public void handleEvent(ResultSetEventObject eo) {
// Code to process the eo ResultSet goes here
}
});