Reputation: 5240
I have following code :
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyThread implements Runnable{
private List<Integer> myList;
public MyThread(List<Integer> list){
this.myList = list;
}
private void updateList(int i){
synchronized (myList) {
myList.add(i);
}
}
@Override
public void run() {
for( int i = 0; i < 1000000;i++){
updateList(i);
}
System.out.println("end: " + myList.size());
}
}
public class MyExecutor {
private List<Integer> taskList = new ArrayList<>();
private void launch(){
ExecutorService executorService= Executors.newFixedThreadPool(10000);
executorService.execute(new MyThread(taskList));
executorService.execute(new MyThread(taskList));
executorService.shutdown();
}
public static void main(String[] args) {
MyExecutor test = new MyExecutor();
test.launch();
}
}
the output should be : 2000000
I will get different result which means these two threads are replacing each other's value.
I can't figure out where is the problem, tried several modifications on this code but none of them has fixed the problem. (replaced with Vector / added synchronize in constructor / added volatile)
Why doesn't this code work correctly?
Edit
At both thread I expect to get 1000000
Upvotes: 1
Views: 99
Reputation: 49606
You are getting
end: 1065878
end: 2000000
The first line is from the thread that has finished its job first. It shouldn't be exactly 1M
, because several threads are working. It's reasonable to assume that by the time one first thread finishes adding its 1M
, the other has added at least one.
The second line is always 2M
(as you expected ) due to the synchronised method.
I guess the first thread should execute for the exact number I wanted, no more no less.
Things happened in parallel. The threads were running. Each was trying to invoke updateList
: one entered, the others waited. There was no priority on who should be next, so the control over the method was being passed among all the workers in a rather random manner.
I bet you are still thinking of the sequential execution :) One thread runs the whole run
method, prints 1M
, the other takes a 1M-sized list and adds its portion.
To understand it better, add a print statement
private void updateList(int i) {
synchronized (myList) {
myList.add(i);
System.out.println(Thread.currentThread().getName() + " added " + i);
}
}
and reduce the number of elements to add by a task to, let's say, 10
.
pool-1-thread-1 added 0
pool-1-thread-1 added 1
pool-1-thread-1 added 2
pool-1-thread-1 added 3
pool-1-thread-2 added 0
pool-1-thread-2 added 1
pool-1-thread-2 added 2
pool-1-thread-2 added 3
pool-1-thread-1 added 4
pool-1-thread-1 added 5
pool-1-thread-1 added 6
pool-1-thread-1 added 7
pool-1-thread-1 added 8
pool-1-thread-1 added 9
end: 14
pool-1-thread-2 added 4
pool-1-thread-2 added 5
pool-1-thread-2 added 6
pool-1-thread-2 added 7
pool-1-thread-2 added 8
pool-1-thread-2 added 9
end: 20
Upvotes: 2
Reputation: 140309
the output should be : 2000000
No, for three reasons:
Upvotes: 3