从线程返回数据类型

时间:2014-12-29 19:56:49

标签: java multithreading jdbc

基本上,我在远程数据库上进行了一些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();
    }

然而,问题是在返回应用程序之前永远不会设置原子布尔值。我试图找到最好的方法来做到这一点,而不会阻止我呼吁的线程。

注意:我知道我应该在这里使用预备语句,试图先弄清楚这一点。

2 个答案:

答案 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
    }
});