2

I am newbie to threading Concept, and I am trying learn....

I came across a situation where i have a Method which returns a List Of Students...and other methods which uses this List to pull Other Details of students Like ParentsName, Sports in which they have participated etc (based on StudentID).. I tried returning a list using following code and it seems like it's not working :(

import java.util.ArrayList;

public class studentClass implements Runnable
{
    private volatile List<Student> studentList;

    @Override
    public void run() 
    {
        studentList = "Mysql Query which is returning StudentList(StudentID,StudentName etc)";  
    }

    public List<Student> getStudentList()
    {
        return studentList;
    }
}

public class mainClass 
{
   public static void main(String args[])
   { 
       StudentClass b = new StudentClass();
       new Thread(b).start();
       // ... 
       List<Student> list = b.getStudentList();
       for(StudentClass sc : b)
       {
           System.out.println(sc);
       }
   }
}

I used this Link - Returning value from Thread the list is NULL.
Where am I going Wrong...???

Community
  • 1
  • 1
goodyzain
  • 683
  • 2
  • 8
  • 21
  • 1
    `studentList="Mysql Query Which is returning StudentList(StudentID,StudentName etc)";` does it compile ? – jmj Jul 15 '14 at 06:54
  • Yes inside thread if print,its Showing Up...@6dsfds32 – goodyzain Jul 15 '14 at 06:55
  • 1
    When you call `start()` on a thread, your program continues to the next line without waiting for the thread to finish. (That's the whole point of running something in a thread.) So you're calling `b.getStudentList()` at a time when the thread's `run()` method might not have assigned a value to the `studentList` yet. – Wyzard Jul 15 '14 at 07:04

4 Answers4

7

Most likely you are not waiting for the result to complete.

A simple solution is to use an ExecutorService instead of creating your own thread pool.

See http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor--

ExecutorService es = Executors.newSingleThreadExecutor();

Future<List<Student>> future = es.submit(new Callable<List<Student>>() {
     public List<Student> call() throws Exception {
          // do some work to get this list
     }
};

// do something

// wait for the result.
List<Student> list = future.get();

This gives to lots more options such as

  • capture any exception thrown so you know what went wrong.
  • pool isDone() to see if it is ready
  • call get() with a tiemout.
  • have a thread pool which re-uses the thread or has more than one thread.
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    @ScaryWombat term of code changes I agree. In terms of a good pattern to use, I suggest using ExecutorService if possible. – Peter Lawrey Jul 15 '14 at 07:02
  • ExecutorService es = Executor.newSingleThreadedPool(); throwing Error newSingleThreadedPool() undefined for type executor..:( – goodyzain Jul 15 '14 at 07:34
  • @goodyzain It is a compiler error (not throwm) telling you I used the wrong class (i have fixed it now) – Peter Lawrey Jul 15 '14 at 07:40
  • Thank you,for the help :):) if i am not wrong...does Executors class have newSingleThreadPool()...????i think u need to change the method name for future users :) :) – goodyzain Jul 15 '14 at 07:56
  • 1
    @goodyzain @Peter It should be `Executors.newSingleThreadExecutor()`. ;) – isnot2bad Jul 15 '14 at 14:24
2

You are getting null since line ArrayList<student> List=b.getStudentList(); is executed before your DB quering happens because that is happening in a separate thread.

You have to wait till database query thread execution finishes. One way to do is to use join() method on the thread.

Thread t = new Thread(new studentClass());
t.start();
t.join();

Or you can use Callable interface provided with Java to return value from a thread. Refer this article as a starting point.

Chathurika Sandarenu
  • 1,368
  • 13
  • 25
0

In the code example, if StudentClass run method will take some seconds, you will print empty since list has not been set.

public class MainClass
{

    public static void main(String args[]) throws Exception
{

    StudentClass b = new StudentClass();

    ExecutorService executorService = Executors.newFixedThreadPool(3);
    Future<List<Student>> studentList = executorService.submit(b);

    // When the thread completed fetching from DB, studentList will have records
    while(studentList.isDone())
    {
        System.out.println("COoolllll" + studentList.get());
    }
}
}

public class StudentClass implements Callable<List<Student>>{

private volatile List<Student> studentList;

public List<Student> getStudentList()
{
    return studentList;
}

@Override
public List<Student> call() throws Exception
{
    /**
     * studentList will fetch from DB
     */
    studentList = new ArrayList<Student>(); 
    return studentList;
}}
sendon1982
  • 9,982
  • 61
  • 44
-1

I think it is good idea to have an global instance of the students list, then call the thread to fill it, and have another bool variable to recognize that the threads work is done or not or something like this.

ConductedClever
  • 4,175
  • 2
  • 35
  • 69