Reputation: 448
I have one global variable in my thread class, which is an ArrayList<>
. I am running this thread periodically from the main()
method; whenever this thread runs, I am populating this list in a run()
method. I want to access this list from my main()
method, but whenever I access this list from main()
, I get an empty list. Please suggest how can I achieve this, following is my code example.
private static ArrayList<SampleClass> allproxyDetailsPojoList = null;
public static void main(String[] args) {
try {
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
Thread.sleep(8000);
SampleThreadClass sampleThreadClass = new SampleThreadClass();
// here i am getting list empty
allproxyDetailsPojoList = sampleThreadClass.getSampleClassList();
} catch (Exception e) {
}
}
and this is my thread class,
public class SampleThreadClass implements Runnable {
ArrayList<SampleClass> sampleClassList = null;
@Override
public void run() {
MyDao myDao = null;
try {
myDao = new MyDao();
sampleClassList = myDao.getSampleClassList();
} catch (Exception e) {
}
}
public ArrayList<SampleClass> getSampleClassList(){
return sampleClassList;
}
}
Note : can not use the static
keyword.
Upvotes: 3
Views: 3207
Reputation: 16084
You need to understand what instances of a class are in contrast of the class definition. In your code you create two instances of the class. Since the variable is not static, each of the instances has its own instance of that variable. You cannot acces instance 1's variable through instance 2's reference.
try {
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
// ^ 1st Instance
Thread.sleep(8000);
SampleThreadClass sampleThreadClass = new SampleThreadClass(); // <-- 2nd Instance
So to use one single instance, change this to
try {
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
SampleThreadClass sampleThreadClass = new SampleThreadClass();
threadSchedulerService.scheduleAtFixedRate(sampleThreadClass , 0, 5, TimeUnit.MINUTES);
Thread.sleep(8000);
But to avoid "strange behavior", I'd also synchronize access to sampleClassList
.
Also, to avoid NPEs I'd change
public ArrayList<SampleClass> getSampleClassList(){
return sampleClassList;
}
to
public ArrayList<SampleClass> getSampleClassList(){
if ( null != sampleClassList )
return sampleClassList;
return Collections.emptyList();
}
But mind that this empty list is immutable. If you need a mutable list, you could just return a new ArrayList<SampleClass>()
.
Using a sleep is not really making this code stable. If you expect a list actually being present after having waited for the service call to be executed at least once, you should do so and not wait for a fixed time period. But that would be another question.
Upvotes: 3
Reputation: 38910
Adding some more info on top of @apadana
answer ( Keep same instance of class, which has been submitted to ExecutorService
)
Once you submit your task to ExecutorService
, your task and main thread runs in parallel. main thread don't get the value until your task has been completed. Since you are accessing the variable with out completion of task, you are getting empty value.
Don't use sleep to populate the value. Instead depend on ExecutorService invokeAll
API or use CountDownLatch
Have a look at working code example:
How to wait for a thread that spawns it's own thread?
Upvotes: 1
Reputation: 14620
You don't need to call start() since you are using executor service. So you are right up to here. However you are creating two different SampleThreadClass. The first one is created here:
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
The second is created here, for which executorservice has no idea of this one because it was never passed to it.
SampleThreadClass sampleThreadClass = new SampleThreadClass();
This is how to fix:
SampleThreadClass sampleThreadClass = new SampleThreadClass();
ScheduledExecutorService threadSchedulerService = Executors.newScheduledThreadPool(1);
threadSchedulerService.scheduleAtFixedRate(sampleThreadClass, 0, 5, TimeUnit.MINUTES);
Thread.sleep(8000);
// here i am getting list empty
allproxyDetailsPojoList = sampleThreadClass.getSampleClassList();
After this fix, the next thing would be for a static variable to be timely visible among threads it should be defined volatile.
Upvotes: 1
Reputation: 1696
You are reading the list of the object you have created in
SampleThreadClass sampleThreadClass = new SampleThreadClass();
and not of the one you have created here and that gets executed:
threadSchedulerService.scheduleAtFixedRate(new SampleThreadClass(), 0, 5, TimeUnit.MINUTES);
This
ArrayList<SampleClass> sampleClassList = null;
is an instance variable, not a global variable.
I think you are getting a null value and not an empty list.
Upvotes: 2
Reputation: 33
Once you make an object of the thread class you need to start the thread. Thread can be started using the start()
function.
When the join()
function is used with the start()
your main program will wait for your thread to execute. Once thread has finished execution your main program will start running.
If you do not use join()
your main program will print the allproxyDetailsPojoList
which is empty, since the thread did not finish execution.
Upvotes: 1