Assume that we have some list of elements and each of them should be processed by the same way. But processing takes a lot of time and we decided to use pool of threads.
In the following example runnable task will just print thread name and input string and then sleep for 2 seconds:
[code language="java" gutter="true" tabsize="4"]
class RunnableTask implements Runnable {
private String data;
public RunnableTask (String data) {
this.data = data;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " processes: " + data);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
//some exception handler
}
}
}[/code]
This is the most important part, we create a thread pool. In our case there will be 3 threads:
[code language="java" gutter="true"]
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class DataProcessor {
private static final int THREAD_NUMBER = 3;
private static final int WAITING_TIMEOUT_IN_DAYS = 1;
public void processData(List<String> someData) {
//creates pool of 3 threads
ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_NUMBER);
for(String data: someData){
//submits task that should be executed
threadPool.submit(new RunnableTask(data));
}
//shutdown to reclaim resources (threads in the pool will exist until shutdown)
threadPool.shutdown();
try {
//blocks shutdown until submitted tasks complete execution
threadPool.awaitTermination(WAITING_TIMEOUT_IN_DAYS, TimeUnit.DAYS);
} catch (InterruptedException e) {
//some exception handler
}
}[/code]
Note that thread pool can be created by several ways. It is possible to use one of the factory methods of
Executors class, that placed in the same package, and also possible to use one of the constructors of corresponding class(ThreadPoolExecutor, ScheduledThreadPoolExscutor, …).In our case, line
[code language="java" firstline="11" gutter="true" tabsize="4"]
ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_NUMBER);[/code]
is equivalent
[code language="java" firstline="11" gutter="true" tabsize="4"]
ExecutorService threadPool = new ThreadPoolExecutor(THREAD_NUMBER, THREAD_NUMBER,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());[/code]
In the most cases factory methods are enough, most settings are already preconfigured there. But if you need some custom solution use constructors.
At the end we'll create a list of elements that should be processed and pass it to our DataProcessor:
[code language="java" firstline="28" gutter="true" tabsize="4"]
public static void main(String[] args){
//list with data for test
List<String> data = new ArrayList<String>();
for(int i=1; i<11; i++){
data.add("Data" + i);
}
//data processing
DataProcessor dataProcessor = new DataProcessor();
dataProcessor.processData(data);
}
}[/code]
In the result you can see something like that:
Really good example, thank you!
ReplyDelete