The setup:
I am in the process of changing the way a program works under the hood. In the current version works like this:
public void threadWork( List<MyCallable> workQueue )
{
ExecutorService pool = Executors.newFixedThreadPool(someConst);
List<Future<myOutput>> returnValues = new ArrayList<Future<myOutput>>();
List<myOutput> finishedStuff = new ArrayList<myOutput>();
for( int i = 0; i < workQueue.size(); i++ )
{
returnValues.add( pool.submit( workQueue.get(i) ) );
}
while( !returnValues.isEmpty() )
{
try
{
// Future.get() waits for a value from the callable
finishedStuff.add( returnValues.remove(0).get(0) );
}
catch(Throwable iknowthisisbaditisjustanexample){}
}
doLotsOfThings(finsihedStuff);
}
But the new system is going to use a private inner Runnable to call a synchronized method that writes the data into a global variable. My basic setup is:
public void threadReports( List<String> workQueue )
{
ExecutorService pool = Executors.newFixedThreadPool(someConst);
List<MyRunnable> runnables = new ArrayList<MyRunnable>()
for ( int i = 0; i < modules.size(); i++ )
{
runnables.add( new MyRunnable( workQueue.get(i) );
pool.submit(threads.get(i));
}
while( !runnables.isEmpty() )
{
try
{
runnables.remove(0).wait(); // I realized that this wouldn't work
}
catch(Throwable iknowthisisbaditisjustanexample){}
}
doLotsOfThings(finsihedStuff); // finishedStuff is the global the Runnables write to
}
If you read my comment in the try of the second piece of code you will notice that I don't know how to use wait(). I had thought it was basically like thread.join() but after reading the documentation I see it is not.
I'm okay with changing some structure as needed, but the basic system of taking work, using runnables, having the runnables write to a global variable, and using a threadpool are requirements.
The Question
How can I wait for the threadpool to be completely finished before I doLotsOfThings()?
You should call ExecutorService.shutdown() and then ExecutorService.awaitTermination.
...
pool.shutdown();
if (pool.awaitTermination(<long>,<TimeUnit>)) {
// finished before timeout
doLotsOfThings(finsihedStuff);
} else {
// Timeout occured.
}
Try this:
pool.shutdown();
pool.awaitTermination(WHATEVER_TIMEOUT, TimeUnit.SECONDS);
Have you considered using the Fork/Join framework that is now included in Java 7. If you do not want to use Java 7 yet you can get the jar for it here.
public void threadReports( List<String> workQueue )
{
ExecutorService pool = Executors.newFixedThreadPool(someConst);
Set<Future<?>> futures = new HashSet<Future<?>>();
for ( int i = 0; i < modules.size(); i++ )
{
futures.add(pool.submit(threads.get(i)));
}
while( !futures.isEmpty() )
{
Set<Future<?>> removed = new Set<Future<?>>();
for(Future<?> f : futures) {
f.get(100, TimeUnit.MILLISECONDS);
if(f.isDone()) removed.add(f);
}
for(Future<?> f : removed) futures.remove(f);
}
doLotsOfThings(finsihedStuff); // finishedStuff is the global the Runnables write to
}
shutdownis a lifecycle method of the ExecutorService and renders the executor unusable after the call. Creating and destroying ThreadPools in a method is as bad as creating/destroying threads: it pretty much defeats the purpose of using threadpool, which is to reduce the overhead of thread creation by enabling transparent reuse.
If possible, you should maintain your ExecutorService lifecycle in sync with your application. - create when first needed, shutdown when your app is closing down.
To achieve your goal of executing a bunch of tasks and waiting for them, the ExecutorService provides the method invokeAll(Collection<? extends Callable<T>> tasks) (and the version with timeout if you want to wait a specific period of time.)
Using this method and some of the points mentioned above, the code in question becomes:
public void threadReports( List<String> workQueue ) {
List<MyRunnable> runnables = new ArrayList<MyRunnable>(workQueue.size());
for (String work:workQueue) {
runnables.add(new MyRunnable(work));
}
// Executor is obtained from some applicationContext that takes care of lifecycle mgnt
// invokeAll(...) will block and return when all callables are executed
List<Future<MyRunnable>> results = applicationContext.getExecutor().invokeAll(runnables);
// I wouldn't use a global variable unless you have a VERY GOOD reason for that.
// b/c all the threads of the pool doing work will be contending for the lock on that variable.
// doLotsOfThings(finishedStuff);
// Note that the List of Futures holds the individual results of each execution.
// That said, the preferred way to harvest your results would be:
doLotsOfThings(results);
}
PS: Not sure why threadReports is void. It could/should return the calculation of doLotsOfThings to achieve a more functional design.
Related
I believe am getting bad data because the instance variable are not thread safe.
I am trying to use multi-threading in a way that opens (at most) 13 threads at a time based on a list. I am using it in a service and need to pass parameters into the run method, so I made some instance variables and set them. I also want those thirteen methods to execute before moving on to the next iteration of the first for loop
private EnergyPortalGroup superGroup;
private EnergyPortalSubGroups singleSubGroup;
private BillingPeriod singlePeriod;
private DateTime[] dateTimeArray;
private void parseGroup(EnergyPortalGroup superGroup) throws InterruptedException{
EnergyPortalSubGroupsCriteria criteria = new EnergyPortalSubGroupsCriteria();
criteria.setGroupId(superGroup.getId());
List<EnergyPortalSubGroups> wholeSubGroupList = subgroupsFactory.readList(criteria);
for (EnergyPortalSubGroups singleSubGroup : wholeSubGroupList){
this.singleSubGroup = singleSubGroup;
this.deleteSubGroupRecordsFromDB(singleSubGroup);
List<BillingPeriod> billingPeriodList = this.getPreviousTwelveBillingPeriods(singleSubGroup, superGroup);
if (billingPeriodList != null && billingPeriodList.size() > 0){
Thread[] threads = new Thread[billingPeriodList.size()];
for (int i = 0; i < billingPeriodList.size(); i++){
this.singlePeriod = billingPeriodList.get(i);
threads[i] = new Thread(this);
threads[i].start();
}
for (Thread thread : threads){
thread.join();
}
}
}
}
Here is my overridden run method:
#Override
public void run(){
List<GroupSummarization> groupSummarizationsToWriteList = new ArrayList<>();
WidgetDataSummationHolder holder = new WidgetDataSummationHolder();
holder = energyPortalService.getEnergyPortalWidgetsSummedData(singleSubGroup, null, null, singlePeriod);
parseSummationHolder(groupSummarizationsToWriteList, holder, singleSubGroup, dateTimeArray, singlePeriod);
processBatchLists(groupSummarizationsToWriteList, superGroup, singlePeriod);
}
Can anyone help me make this thread safe? I am obviously new to multithreading and I tried passing these variables in with a constructor but I have some autowired services that were null and I was getting a null pointer at this line holder = energyPortalService.getEnergyPortalWidgetsSummedData(singleSubGroup, null, null, singlePeriod);
energyPortalService cannot be null sometimes and not other times, given the code you provided. If it is not null when you launch a new Thread(this), then it should be there if you would use a new Thread(()-> {...});
(since you are talking about autowiring, I will presume a whole lot of foul play can occur with osgi and aop and such evils.)
In the end, I went with ExecutorService and a new class/service like a few suggested. So here is an example in case anyone else runs into this type of problem:
for (final Object x : list){
List<Object> someList = getList();
if (!Collections.isEmpty(someList)){
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<?>> futures = new ArrayList<Future<?>>();
for (final Object n : someList){
futures.add(executorService.submit(new Runnable(){
#Override
public void run(){
someOtherService.process(parameters)
}
}));
}
for (Future<?> f : futures){
try {
f.get();
} catch (InterruptedException | ExecutionException e) {
//do some logging
}
}
}
}
Basically this is calling an ExecutorService that manages the thread pool. I call newCachedThreadPool so that it creates new threads as needed instead of just assuming I know how many threads I would need in this case if you do see newFixedThreadPool(n). But, to ensure I get some consistency on thread size, after I loop through the inner loop, I loop through the futures list (a future is a future result of an asynchronous computation) and call f.get which waits if necessary for the computation to complete, and then retrieves its result...
This worked great for what I needed. And the key part is that inside of the overridden run function, the process method takes whatever parameters you want (notice the use of final) instead of trying to force feed run() or worrying about an autowired service when you are calling a constructor. This bypasses all of that.
Thank you to all who put me on the correct path
I'm writing a game engine which performs alhpa-beta search on at a game state, and I'm trying to parallelize it. What I have so far is working at first, and then it seems to slow to a halt. I suspect that this is because I'm not correctly disposing of my threads.
When playing against the computer, the game calls on the getMove() function of a MultiThreadedComputerPlayer object. Here is the code for that method:
public void getMove(){
int n = board.legalMoves.size();
threadList = new ArrayList<WeightedMultiThread>();
moveEvals = new HashMap<Tuple, Integer>();
// Whenever a thread finishes its work at a given depth, it awaits() the other threads
// When all threads are finished, the move evaluations are updated and the threads continue their work.
CyclicBarrier barrier = new CyclicBarrier(n, new Runnable(){
public void run() {
for(WeightedMultiThread t : threadList){
moveEvals.put(t.move, t.eval);
}
}
});
// Prepare and start the threads
for (Tuple move : board.legalMoves) {
MCBoard nextBoard = board.clone();
nextBoard.move(move);
threadList.add(new WeightedMultiThread(nextBoard, weights, barrier));
moveEvals.put(move, 0);
}
for (WeightedMultiThread t : threadList) {t.start();}
// Let the threads run for the maximum amount of time per move
try {
Thread.sleep(timePerMove);
} catch (InterruptedException e) {System.out.println(e);}
for (WeightedMultiThread t : threadList) {
t.stop();
}
// Play the best move
Integer best = infHolder.MIN;
Tuple nextMove = board.legalMoves.get(0);
for (Tuple m : board.legalMoves) {
if (moveEvals.get(m) > best) {
best = moveEvals.get(m);
nextMove = m;
}
}
System.out.println(nextMove + " is the choice of " + name + " given evals:");
for (WeightedMultiThread t : threadList) {
System.out.println(t);
}
board.move(nextMove);
}
And here run() method of the threads in question:
public void run() {
startTime = System.currentTimeMillis();
while(true) {
int nextEval = alphabeta(0, infHolder.MIN, infHolder.MAX);
try{barrier.await();} catch (Exception e) {}
eval = nextEval;
depth += 1;
}
}
I need to be able to interrupt all the threads when time is up-- how am I supposed to implement this? As of now I'm constantly catching (and ignoring) InterruptedExceptions.
Thread.stop was deprecated for a reason. When you interrupt a thread in the middle, the thread doesn't have the chance to properly release resources it was using, and doesn't notify other threads of its completion...something that's very important in multi-threaded apps. I'm not surprised your performance tanks; I would be willing to bet your memory usage shoots through the roof. You also don't recycle the threads, you start and stop them without creating new objects, which means whatever broken state the variables were left in is probably still plaguing them.
A better way is to set a flag that tells the thread it should return. So include in your WeightedMultiThread class a boolean named something like shouldQuit, and set it to false every time start() is called. Then, instead of while (true) do while (!shouldQuit), and instead of t.stop(), use t.shouldQuit = true. After you do that to every thread, have another loop that checks each thread for t.isAlive(), and once every thread has returned, go about your business. You should have much better results that way.
This looks like an ideal place to use an ExecutorService. You can create Callable instances that implement the parallel tasks, submit them to the ExecutorService, then use awaitTermination to enforce a timeout.
For example:
public void getMove() {
ExecutorService service = Executors.newFixedThreadPool(board.legalMoves.size());
List<Future<Something>> futures = new ArrayList<Future<Something>>(board.legalMoves.size());
for (Tuple move : board.legalMoves) {
futures.add(service.submit(new WeightedMultiThread(...)));
}
service.awaitTermination(timePerMove, TimeUnit.MILLISECONDS);
service.shutdownNow(); // Terminate all still-running jobs
for (Future<Something> future : futures) {
if (future.isDone()) {
Something something = future.get();
// Add best move logic here
}
}
...
}
Replace Something with something that encapsulates information about the move that has been evaluated. I'd suggest Something be a class that holds the Tuple and its associated score. Your WeightedMultiThread class can do something like this:
class WeightedMultiThread implements Callable<Something> {
public Something call() {
// Compute score
...
// Return an appropriate data structure
return new Something(tuple, score);
}
}
Even better would be to create the ExecutorService once and re-use it for each call to getMove. Creating threads is expensive, so best to only do it once if you can. If you take this approach then you should not call shutdownNow, but instead use the Future.cancel method to terminate jobs that have not completed in time. Make sure your WeightedMultiThread implementation checks for thread interruption and throws an InterruptedException. That's usually a good way to write a long-running task that needs to be interruptible.
EDIT:
Since you're doing a level-by-level exploration of the game space, I'd suggest that you encode that in the getMove function rather than in the Tuple evaluation code, e.g.
public Tuple getMove() {
ExecutorService service = ...
Tuple best = null;
long timeRemaining = MAX_TIME;
for (int depth = 0; depth < MAX_DEPTH && timeRemaining > 0; ++depth) {
long start = System.currentTimeMillis();
best = evaluateMoves(depth, service, timeRemaining);
long end = System.currentTimeMillis();
timeRemaining -= (end - start);
}
return best;
}
private Tuple evaluateMoves(int depth, ExecutorService service, long timeRemaining) {
List<Future<Whatever>> futures = service.submit(...); // Create all jobs at this depth
service.awaitTermination(timeRemaining, TimeUnit.MILLISECONDS);
// Find best move
...
return best;
}
That could probably be cleaner, but you get the idea.
The most sensitive way is to use interruption mechanism. Thread.interrupt() and Thread.isInterrupted() methods. This ensures your message will be delivered to a thread even if it sits inside a blocking call (remember some methods declare throwing InterruptedException?)
P.S. It would be useful to read Brian Goetz's "Java Concurrency in Practice" Chapter 7: Cancellation and Shutdown.
I am developing a program that can send http requests to fetch documents.
I have fill a queue with all the requests items:
Queue<RequestItem> requestItems = buildRequest4Docs();
Then,
int threadNum = requestItems.size();
//ExecutorService exs = Executors.newFixedThreadPool(threadNum);
for (int i = 0; i < threadNum; i++) {
ResponseInterface response = new CMSGOResponse();
RequestTask task = new RequestTask(requestItems.poll(), this, response);
task.run();
//exs.execute(new RequestTask(requestItems.poll(), this, response));
}
//exs.shutdown();
I am confused here, in the for loop,does the tasks run simultaneously? Or the tasks run one by one?
Thanks!
In the way you got it now the tasks will be executed one by one. If you uncomment the code you got now as comments and comment the lines RequestTask task = new RequestTask(requestItems.poll(), this, response); and task.run(); you will get a concurrent execution.
So for the concurrent execution it has to look like this:
int threadNum = requestItems.size();
ExecutorService exs = Executors.newFixedThreadPool(threadNum);
for (int i = 0; i < threadNum; i++) {
ResponseInterface response = new CMSGOResponse();
exs.execute(new RequestTask(requestItems.poll(), this, response));
}
exs.shutdown();
while (! exs.isTerminated()) {
try {
exs.awaitTermination(1L, TimeUnit.DAYS);
}
catch (InterruptedException e) {
// you may or may not care here, but if you truly want to
// wait for the pool to shutdown, just ignore the exception
// otherwise you'll have to deal with the exception and
// make a decision to drop out of the loop or something else.
}
}
In addition to that I suggest, that you do not bind the amount of threads created with the ExecutorService to the amount of task you got to work. Connecting it to the amount of processors of the host system is usually a better method. To get the amount of processors use: Runtime.getRuntime().availableProcessors()
And in the executor service initialized like this you put the items of your queue. But that works nicely without fetching the total size, rather by polling the Queue until it does not return additional data.
The final result of my proposals could look like this:
final int threadNum = Runtime.getRuntime().availableProcessors();
final ExecutorService exs = Executors.newFixedThreadPool(threadNum);
while (true) {
final RequestItem requestItem = requestItems.poll();
if (requestItem == null) {
break;
}
final ResponseInterface response = new CMSGOResponse();
exs.execute(new RequestTask(requestItem , this, response));
}
exs.shutdown();
I am confused here, in the for loop,does the tasks run simultaneously? Or the tasks run one by one?
With the code you've posted, they'll run one-by-one, because (assuming RequestTask is a subclass of Thread) you've called run. You should call start. Now that you've said RequestTask implements Runnable, the correct code wouldn't call start (it doesn't have one!) but rather new Thread(task);. (But it looks like you've now received a good answer regarding the ExecutorService, which is another way to do it.)
Assuming you call start start them on different threads instead, then yes, they'll all run in parallel (as much as they can on the hardware, etc.).
Currently you are running your thread sequentially, Well you have two ways to run threads.(Assuming that RequestTask extends Thread)
I.Either create thread object and call start() method.
RequestTask task = new RequestTask(requestItems.poll(), this, response);
task.start(); // run() method will be called, you don't need to call it
II.Or create ExecutorService
ExecutorService pool = Executors.newFixedThreadPool(poolSize);
//....
for (int i = 0; i < threadNum; i++) {
ResponseInterface response = new CMSGOResponse();
RequestTask task = new RequestTask(requestItems.poll(), this, response);
pool.execute(task);
}
You are running them one by one in the current thread. You need to use the ExecutorService to run them concurrently.
I am confused here, in the for loop,does the tasks run simultaneously? Or the tasks run one by one?
Task will be executed in the same thread i.e. one by one since you are calling run() rather that start , it will not run the task in new thread .
int threadNum = requestItems.size();
ExecutorService exs = Executors.newFixedThreadPool(threadNum);
ResponseInterface response = new CMSGOResponse();
RequestTask task = new RequestTask(requestItems.poll(), this, response);
exs.execute(task );
exs.shutdown();
In above case task will be executed in new thread and as soon as you assign 10 different task to ExecutorService they will be executed asynchronously in different threads.
I usually tend to create my Threads (or classes implementing Interface), THEN launch them with the start() method.
In your case, since RequestTask implements Runnable, you could add a start() method like this :
public class RequestTask implements Runnable {
Thread t;
boolean running;
public RequestTask() {
t = new Thread(this);
}
public void start() {
running = true; // you could use a setter
t.start();
}
public void run() {
while (running) {
// your code goes here
}
}
}
, then :
int threadNum = requestItems.size();
RequestTask[] rta = new RequestTask[threadNum];
// Create the so-called Threads ...
for (int i=0;i<threadNum;i++) {
rta[i] = new RequestTask(requestItems.poll(), this, new CMSGOResponse());
}
// ... THEN launch them
for (int i=0;i<threadNum;i++) {
rta[i].start();
}
I would like to know if there's a way to monitor the life of a thread but I'll explain the context of what I'm doing so maybe there's a better way to do this.
Basically I have x threads that are working on a queue and processing it, if a thread gets a acceptable result it goes into a solutions queue otherwise the data is either discarded or further processed.
My problem is in my main thread I have a like while(!solutions_results.isEmpty()) and it saves the data(right now its print to a file but later maybe database). The obvious problem is once it clears the solutions queue its done and finishes working even though the other threads are still putting data into the queue.
I'm not sure the best way to deal with this(maybe have a dedicated thread that only saves the solution queue?) but I was thinking if I could somehow monitor the life of the other threads are done then there's no chance of more data going into the solutions queue.
if there's a better way to do this please let me know otherwise is there a way to tell once the other threads are done(I can't wait for executor to completely finish before running this process because it can get quite large and don't want it to just sit in memory, ideally want to process it as it close to as it comes in but its not time dependent)?
If you use the ExecutorService to run your thread jobs then you can use the awaitTermination() method to know when all of the threads have finished:
ExecutorService pool = Executors.newFixedThreadPool(10);
pool.submit(yourSolutionsRunnable);
pool.submit(yourSolutionsRunnable);
...
// once you've submitted your last job you can do
pool.shutdown();
Then you can wait for all of the jobs submitted to finish:
pool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
This would get more complicated if your threads need to keep running after submitting their solutions. If you edit your question and make this more apparent I'll edit my answer.
Edit:
Oh, I see you want to process some results along the way but not stop until all of the threads are done.
You can use the pool.isTerminated() test which will tell you if all of the jobs have completed. So your loop would look something like:
// this is the main thread so waiting for solutions in a while(true) loop is ok
while (true) {
// are all the workers done?
if (pool.isTerminated()) {
// if there are results process one last time
if (!solutions_results.isEmpty()) {
processTheSolutions();
}
break;
} else {
if (solutions_results.isEmpty()) {
// wait a bit to not spin, you could also use a wait/notify here
Thread.sleep(1000);
} else {
processTheSolutions();
}
}
}
Edit:
You could also have two thread pools, one for generating the solutions and another one processing. Your main thread could then wait for the worker pool to empty and then wait for the solutions processing pool. The worker pool would submit the solutions (if any) into the solutions pool. You could just have 1 thread in the solutions processing pool or more as necessary.
ExecutorService workerPool = Executors.newFixedThreadPool(10);
final ExecutorService solutionsPool = Executors.newFixedThreadPool(1);
solutionsPool.submit(workerThatPutsSolutionsIntoSolutionsPool);
...
// once you've submitted your last worker you can do
workerPool.shutdown();
workerPool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
// once the workers have finished you shutdown the solutions pool
solutionsPool.shutdown();
// and then wait for it to finish
solutionsPool.waitTermination(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
I don't know much about the behavior requirements that you're dealing with but if you want the main thread to block until all your child threads are complete you should take a look at the join method of the Thread class.
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#join()
Just run a loop inside your main thread that calls the join method on each one of your child threads and when it exits the loop you can be sure that all threads have finished working.
Just keep a list of your active threads. You'd want it synchronized to keep it from being trashed if you add/remove threads simultaneously. Or use something like java.util.concurrent.ConcurrentLinkedQueue, which can deal with multiple threads itself. Add each thread to the list when you start it. Each thread should remove itself from the list right before it stops. When the list is empty, all your threads are done.
Edit: the timing is important. First, the main thread has to put the working threads into the list. If they put themselves into the list, the main thread could check the list at a time when some threads have removed themselves from the list and all the rest, though started, have not yet begun executing--and so not yet put themselves in the list. It would then think everything was done when it wasn't. Second, the main thread must put each worker thread on the list before it starts it. Otherwise, the thread might finish and make its attempt to remove itself from the list before the main thread adds it to the list. Then the list will never become empty and the program will never finish.
Maybe java.util.concurrent.ExecutorCompletionService would be useful here.
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class monitor_life_of_threads
{
/**
* First, convert all of your threads to instances of Callable (easy to do), and have them each return an instance some class (I'm using Integer below just as
* an example).
* This will help simplify things.
*/
public static void main ( String args[] )
{
final monitor_life_of_threads worker = new monitor_life_of_threads();
worker.executeCallablesAndUseResults ();
System.exit ( 0 );
}
private void executeCallablesAndUseResults ()
{
List < Callable < Result >> list = new ArrayList <> ();
populateInputList ( list );
try
{
doWork ( list );
}
catch ( InterruptedException e )
{
e.printStackTrace ();
}
catch ( ExecutionException e )
{
e.printStackTrace ();
}
catch ( CancellationException e )
{
/*
* Could be called if a Callable throws an InterruptedException, and if it's not caught, it can cause Future.get to hang.
*/
e.printStackTrace ();
}
catch ( Exception defaultException )
{
defaultException.printStackTrace ();
}
}
private void doWork ( Collection < Callable < Result >> callables ) throws InterruptedException, ExecutionException
{
ExecutorService executorService = Executors.newCachedThreadPool ();
CompletionService < Result > ecs = new ExecutorCompletionService < > ( executorService );
for ( Callable < Result > callable : callables )
ecs.submit ( callable );
for ( int i = 0, n = callables.size (); i < n; ++i )
{
Result r = ecs.take ().get ();
if ( r != null )
use ( r ); // This way you don't need a second queue.
}
executorService.shutdown ();
}
private void use ( Result result )
{
// Write result to database, output file, etc.
System.out.println ( "result = " + result );
}
private List < Callable < Result >> populateInputList ( List < Callable < Result >> list )
{
list.add ( new Callable < Result > () {
#Override
public Result call () throws Exception
{
// Do some number crunching, then return a 5.
return new Result ( 5 );
}
} );
list.add ( new Callable < Result > () {
#Override
public Result call () throws Exception
{
// Do some number crunching, then return an 8.
return new Result ( 8 );
}
} );
list.add ( new Callable < Result > () {
#Override
public Result call () throws Exception
{
// Do some number crunching, but fail and so return null.
return null;
}
} );
return list;
}
}
class Result
{
private Integer i;
Result ( Integer i)
{
this.i = i;
}
public String toString ()
{
return Integer.toString ( i );
}
}
I have a .csv file containing over 70 million lines of which each line is to generate a Runnable and then executed by threadpool. This Runnable will insert a record into Mysql.
What's more , I want to record a position of the csv file for the RandomAccessFile to locate. The position is written to a File.I want to write this record when all the threads in threadpool are finished.So ThreadPoolExecutor.shutdown() is invoked. But when more lines come, I need a threadpool again. How can I reuse this current threadpool instead of make a new one.
The code is as follows:
public static boolean processPage() throws Exception {
long pos = getPosition();
long start = System.currentTimeMillis();
raf.seek(pos);
if(pos==0)
raf.readLine();
for (int i = 0; i < PAGESIZE; i++) {
String lineStr = raf.readLine();
if (lineStr == null)
return false;
String[] line = lineStr.split(",");
final ExperienceLogDO log = CsvExperienceLog.generateLog(line);
//System.out.println("userId: "+log.getUserId()%512);
pool.execute(new Runnable(){
public void run(){
try {
experienceService.insertExperienceLog(log);
} catch (BaseException e) {
e.printStackTrace();
}
}
});
long end = System.currentTimeMillis();
}
BufferedWriter resultWriter = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(new File(
RESULT_FILENAME), true)));
resultWriter.write("\n");
resultWriter.write(String.valueOf(raf.getFilePointer()));
resultWriter.close();
long time = System.currentTimeMillis()-start;
System.out.println(time);
return true;
}
Thanks !
As stated in the documentation, you cannot reuse an ExecutorService that has been shut down. I'd recommend against any workarounds, since (a) they may not work as expected in all situations; and (b) you can achieve what you want using standard classes.
You must either
instantiate a new ExecutorService; or
not terminate the ExecutorService.
The first solution is easily implemented, so I won't detail it.
For the second, since you want to execute an action once all the submitted tasks have finished, you might take a look at ExecutorCompletionService and use it instead. It wraps an ExecutorService which will do the thread management, but the runnables will get wrapped into something that will tell the ExecutorCompletionService when they have finished, so it can report back to you:
ExecutorService executor = ...;
ExecutorCompletionService ecs = new ExecutorCompletionService(executor);
for (int i = 0; i < totalTasks; i++) {
... ecs.submit(...); ...
}
for (int i = 0; i < totalTasks; i++) {
ecs.take();
}
The method take() on the ExecutorCompletionService class will block until a task has finished (either normally or abruptly). It will return a Future, so you can check the results if you wish.
I hope this can help you, since I didn't completely understand your problem.
create and group all tasks and submit them to the pool with invokeAll (which only returns when all tasks are successfully completed)
After calling shutdown on a ExecutorService, no new Task will be accepted. This means you have to create a new ExecutorService for each round of tasks.
However, with Java 8 ForkJoinPool.awaitQuiescence was introduced. If you can switch from a normal ExecutorService to ForkJoinPool, you can use this method to wait until no more tasks are running in a ForkJoinPool without having to call shutdown. This means you can fill a ForkJoinPool with Tasks, waiting until it is empty (quiescent), and then again begin filling it with Tasks, and so on.