Like some of the suggested comments, the problem is locking (i.e., in the synchronized(this) ). Synchronization is performed on this , which in your case is the only instance of MyRunnable , therefore, while one thread does work inside the synchronized block, all other threads will wait until the operation is completed. Thus, only one thread does the real work at a time.
Here's how to solve the problem. Since you need your threads to work on different lines in parallel, this work should not be synchronized by locking (since locking means the opposite: only one thread can do the work at a time). What you need to synchronize is the part in which each thread determines which line it will run on.
Here is an example of pseudo code:
public void run(){ int workRow; synchronized(this){ workRow = findNextUnprosessedRow(); } for(int i=0; i<matrix[workRow].length; i++){
Please note that the actual work is intentionally not synchronized for the reasons mentioned above.
The way you use threads is correct, so there is no problem with this, however I would suggest you take a look at the Java concurrency API: Thread Pools . Here is an example of how to use it in your context:
//Creates a pool of 5 concurrent thread workers ExecutorService es = Executores.newFixedThreadPool(5); //List of results for each row computation task List<Future<Void>> results = new ArrayList<Future<Void>>(); try{ for(int row=0; row<matrix.length; row++){ final int workRow = row; //The main part. You can submit Callable or Runnable // tasks to the ExecutorService, and it will run them // for you in the number of threads you have allocated. // If you put more than 5 tasks, they will just patiently // wait for a task to finish and release a thread, then run. Future<Void> task = es.submit(new Callable<Void>(){ @Override public Void call(){ for(int col=0; col<matrix[workRow].length; col++){ //do something for each column of workRow } return null; } }); //Store the work task in the list. results.add(task); } }finally{ //Make sure thread-pool is shutdown and all worker //threads are released. es.shutdown(); } for(Future<Void> task : results){ try{ //This will wait for threads to finish. // ie same as Thread.join() task.get(); }catch(ExecutionException e){ //One of the tasks threw an exception! throw new RuntimeException(e); } }
This approach is much cleaner because the distribution of work is done mainly by thread (external to the loop) and therefore there is no need to synchronize it.
You also get some bonuses when working with thread pools:
He takes great care of all exceptions during the calculations in each thread. When working with bare threads, as in your approach, it is easy to โloseโ the exception.
Streams are combined. That is, they are automatically reused, so you donโt have to worry about the cost of spawning new threads. This is especially useful in your case, since you will need to spawn a stream in a row in your matrix, which can be quite large, I suspect.
The tasks presented by ExecutorService are wrapped in a useful Future<Result> object, which is most useful when each calculation task actually returns some kind of result. In your case, if you need to sum all the values โโin the matrix, then each calculation task can return the sum for the row. Then you just need to take stock.
Got some time, but hope he clears some things.