Reputation: 1215
Trying to figure out how threading in Java works, i just want to limit runnable threads executing by putting them all to array and then check in loop if some of them finished and pop them out, to have possibility to spawn a new thread, got exception in this code:
public class testThread implements Runnable {
public void run () {
try {
Thread.sleep(1000);
} catch(InterruptedException e){}
System.out.println("This is the test thread");
}
public static void main (String args[]) {
int max_threads = 5;
Thread worker;
ArrayList<Thread> all_workers = new ArrayList<Thread>(max_threads );
for (int i =0; i<50; i++) {
if (all_workers.size()<max_threads){
worker = new Thread (new testThread());
all_workers.add(worker);
worker.start();
} else{
System.out.println("i ran all");
while(all_workers.size()>=max_threads){
try{
System.out.println("Waiting for some to finish");
int counter = 0;
for (Thread wrk: all_workers){
if (!wrk.isAlive()){
all_workers.remove(counter);
}
counter ++ ;
}
Thread.sleep(500);
} catch (InterruptedException e){
System.out.println("Catched unhandled ");
}
}
}
}
for(Thread wrk: all_workers){
try {
wrk.join();
} catch (InterruptedException e) {
}
}
}
}
exception i got when i run it:
anybody@anymachine ~/java $ java testThread
i ran all
Waiting for some to finish
Waiting for some to finish
This is the test thread
This is the test thread
This is the test thread
This is the test thread
This is the test thread
Waiting for some to finish
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at testThread.main(testThread.java:39)
thank you for any help, if there is a good tutorial i would be much appriciated for link.
PS. if there is any debugger in java like pdb in python please let me know. thank you!
Upvotes: 2
Views: 7967
Reputation: 116918
Exception in thread "main" java.util.ConcurrentModificationException
You are getting this because you are removing from an ArrayList
while you are iterating across it. This is not allowed.
for (Thread wrk : all_workers) {
if (!wrk.isAlive()) {
// ERROR, you can't change the collection while you are in a for loop
all_workers.remove(counter);
}
...
If you need to remove from a list you are walking across, you should use the iterator.remove()
instead:
Iterator<Thread> iterator = all_workers.iterator();
while (interator.hasNext()) {
Thread wrk = interator.next();
if (!wrk.isAlive()) {
// this is allowed because you are using the iterator directly
iterator.remove();
}
}
A better solution to your specific situation is to use the ExecutorService
code. What you do then is to create a fixed thread pool and submit your jobs to it:
// create a thread pool with 5 worker threads
ExecutorService threadPool = Executors.newFixedThreadPool(5);
// define your jobs somehow
for (int i = 0; i < 50; i++) {
threadPool.submit(new testThread());
}
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
// then wait for it to complete
threadPool.awaitTermination(Long.MAX_LONG, TimeUnit.MILLISECONDS);
Upvotes: 6
Reputation: 12029
You should have a look at the higher level threading utilities like ExecutorService and ThreadPools.
You should never terminate a thread manually and I suggest to avoid manual thread creation/management in general.
If you want to wait for a number of threads finishing, you may want to use a CountDownLatch. Here is an example.
Upvotes: 7
Reputation: 13535
First, why do you need to limit the number of running threads? Note, computer cannot simultaneously run more threads than it has processors anyway.
The main drawback of your solution is Thread.sleep(500)
. It causes unnecessary latency.
The right solution is to use a java.util.Executor
with desired number of threads. Then you simply call executor.execute(new testThread())
instead of new Thread (new testThread()).start()
.
Upvotes: 1
Reputation: 19270
Change the below line
ArrayList<Thread> all_workers = new ArrayList<Thread>(max_threads);
To
Set<Thread> all_workers = Collections.newSetFromMap(new ConcurrentHashMap<Thread,Boolean>())
Upvotes: 0