Reputation: 2014
Is there an elegant way to do that? Or it can always be avoided because one can use a better design patter?
import java.util.ArrayList;
import java.util.List;
public class ForTest {
List<String> ls = new ArrayList<String>();
public static void main(String[] args) {
ForTest forTest=new ForTest();
System.out.println(forTest.ls.size());
new Thread(new Worker(forTest.ls)).start();
//size() does not change at all
System.out.println(forTest.ls.size());
}
}
class Worker implements Runnable{
List<String> list;
public Worker(List<String> li) {
this.list = li;
}
public void run(){
this.list.add("newItem");
}
}
Upvotes: 0
Views: 122
Reputation: 51711
You need to make your main thread sleep()
for a while. The size()
is getting called before the new Thread
gets a chance to update it.
new Thread(new Worker(forTest.ls)).start();
Thread.sleep(2000);
System.out.println(forTest.ls.size());
An even better way would be to join()
on to the worker thread. This would make the main thread automatically wake up when the worker is finished.
Thread worker = new Thread(new Worker(forTest.ls));
worker.start();
worker.join();
System.out.println(forTest.ls.size());
In addition to that make use of a synchronized ArrayList
to prevent a race condition if the List would be shared and modified by multiple threads.
List<String> ls = Collections.synchronizedList(new ArrayList<String>());
Upvotes: 2
Reputation: 7166
wait for the new thread to actually start running your code + make forTest
final to be able to access it (also use a thread-safe collection - best non-synchronous a.k.a. non-blocking) e.g.
import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ForTest {
Collection<String> ls = new ConcurrentLinkedQueue<String>();
public static void main(String[] args) throws InterruptedException {
final ForTest forTest = new ForTest();
System.out.println(forTest.ls.size());
int threads = 10;
for ( int i=0; i<threads; i++ ) {
new Thread(new Runnable() {
@Override
public void run() {
forTest.ls.add("newItem");
}
}).start();
}
Thread.sleep(1000);// wait for it !
System.out.println(forTest.ls.size()); // 10 unless your threads are really slow
}
}
Upvotes: 1
Reputation: 436
Please note that ArrayList
is not synchronized, but Vector
is. You cannot expect the worker to run just a moment after you started its thread. That's why the list size is not changed yet. I guess this is not your complete example, so it is difficult to help you. (If this was your complete example I would wonder why you bother implementing a multi-threaded solution.)
For knowing when the worker finished you could join the threads.
Upvotes: 1
Reputation: 4087
You seem to be missing the idea of Threading. Your code will not work because your worker has likely not updated ls by the time you print it. If you're using threading, the threads need to communicate state. This is all quite complex, I suggest you read the java tutorials on threading http://docs.oracle.com/javase/tutorial/essential/concurrency/
Upvotes: 1
Reputation: 328618
There are several issues with your code (in particular you use ArrayList which is not thread safe without proper synchronization).
But the most obvious one is that the second println statement is almost always going to be called before your run
method has had a chance to be executed.
Upvotes: 2