简体   繁体   中英

Java have thread return something to main thread

I'm stuck on something, and can't seem to think of a solution. I have a function called dbSelect, which then creates a thread to run a MySQL query and get a ResultSet , but then I need my dbSelect to get that ResultSet and return it. Here's what I have:

public class Utils {
    public static void dbSelect(String query){
        selectQuery = query;
        Thread selectThread = new selectThreadClass();
        selectThread.start();
    }
}
class selectThreadClass extends Thread {
    public void run(){
        perform();
    }

    public ResultSet perform(){
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            conn = DriverManager.getConnection("jdbc:mysql://localhost/lob/?user=root&password=");

            Statement s = conn.createStatement();
            ResultSet rs = s.executeQuery(Utils.selectQuery);
            return rs;
        }catch (SQLException | InstantiationException | IllegalAccessException | ClassNotFoundException e){
            e.printStackTrace();
            return null;
        }
    }
}

Can anyone help me get it so that dbSelect returns the ResultSet from the thread? Thanks!

Use Callable

 public interface Callable<V> {
 V call() throws Exception;
}

Instead of Runnable Use callable.

public class SelectCallableClass implements Callable<ResultSet> {

    public ResultSet call() throws Exception {
        return perform();
    }

    public ResultSet perform(){
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            conn = DriverManager.getConnection("jdbc:mysql://localhost/lob/?user=root&password=");

            Statement s = conn.createStatement();
            ResultSet rs = s.executeQuery(Utils.selectQuery);
            return rs;
        }catch (SQLException | InstantiationException | IllegalAccessException | ClassNotFoundException e){
            e.printStackTrace();
            return null;
        }
    }
}

To submit Callable class, use the ExecuterService

ExecutorService service=Executors.newFixedThreadPool(1);
Future future=service.submit(new SelectCallableClass());

The above code does the following(from doc).Submits a value-returning task for execution and returns a Future> representing the pending results of the task. The Future's get method will return the task's result upon successful completion.

just a try from my end

I modified the code and got the solution using List to hold the value from the ResultSet but I just have one question and that is, I was not able to get the result as type (ResultSet) in Callable

Somehow the result set was empty when I tried to retrieve the value using the future get() function

ResultSet rs = (ResultSet)future.get();

Below is the piece of code which didnt work,

ExecutorService service=Executors.newFixedThreadPool(1);
Callable<ResultSet> callable = new SelectThreadResultSet();
Future<ResultSet> future = service.submit(callable);
ResultSet rs = (ResultSet)future.get();
// Here I dont get any values
while(rs.next()){
    System.out.println(rs.getString("EMPLOYEE"));
}

Please find below the solution which worked for me, I used List to hold the values and returned it.

class SelectThreadClass:

public class SelectThreadClass implements Callable<List<String>> {

    public List<String> call(){
        ResultSet rs = null;
        List<String> strList = new ArrayList<String>();
        try {
            rs  = perform();
            while(rs.next()){
                strList.add(rs.getString("EMPNAME"));
            }
            System.out.println("Passed");

        } catch (InstantiationException | IllegalAccessException | SQLException e) {
            e.printStackTrace();
        }
        return strList;
    }

    public ResultSet perform() throws InstantiationException, IllegalAccessException, SQLException{
        Connection conn = null;
        try {
            Class.forName("org.sqlite.JDBC");
            try {
                conn = DriverManager.getConnection("jdbc:sqlite:C:\\SqlLite\\EMPLOYEE.db");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            Statement s = null;
            try {
                s = conn.createStatement();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            ResultSet rs = null;
            try {
                rs = s.executeQuery(Utils.selectQuery);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return rs;
        }catch (ClassNotFoundException e){
            e.printStackTrace();
            return null;
        }
    }
}

class Utils:

public class Utils {

    public static String selectQuery = "SELECT EMPNAME FROM EMPLOYEEDETAILS";
    public static void dbSelect(String query) throws InterruptedException, ExecutionException, SQLException{
        ExecutorService service=Executors.newFixedThreadPool(1);
        Callable<List<String>> callable = new SelectThreadClass();

        Future<List<String>> future = service.submit(callable);

        List<String> empList = future.get();
        for(String emp : empList){
            System.out.println(emp);
        }
    }

    public static void main(String args[]) throws InterruptedException, ExecutionException, SQLException{
        dbSelect("SELECT EMPNAME FROM EMPLOYEEDETAILS");
    }

}

run does not return a result.
Either use al Callable or use a shared variable and poll/ wait in Utils until the result from the SelectThreadClass is available.
But I recommend to use a Callable as it fits exactly for the task

You can simply have an attribute in your Thread class and then get hold of that attribute,

public class Utils {
    public static void dbSelect(String query){
        selectQuery = query;
        Thread selectThread = new selectThreadClass();
        selectThread.start();

        ((SelectThreadClass) selectThread).getResult();
    }
}

class selectThreadClass extends Thread {
    ResultSet rs = null;

    public ResultSet getResult(){
        return rs;
    }

    public void run(){
        rs = perform();
    }

    public ResultSet perform(){
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver").newInstance();
            conn = DriverManager.getConnection("jdbc:mysql://localhost/lob/?user=root&password=");

            Statement s = conn.createStatement();
            return s.executeQuery(Utils.selectQuery);
        } catch (SQLException | InstantiationException | IllegalAccessException | ClassNotFoundException e){
            e.printStackTrace();
            return null;
        }
    }
}

the only problem is that you might end up handling the connection closure and other stuff out of your dbutil, alternatively , you can convert the result set to whatever java class and then return that java object list rather result set

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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