I have an array of 32 cache objects and I am refreshing each of the cache periodically after every 20 seconds. Attached code snippet below.
I am observing that few caches stops refreshing after some refresh cycles and there is no exception printed in the logs. Note that application is not crashing, but some caches are not getting refreshed.
public class CacheManager
{
private static class CacheRefresher extends Thread
{
Cache cache;
public CacheRefresher(Cache cache)
{
this(cache);
}
#Override
public final void run()
{
try {
LOG.info("cache is getting refreshed for " + cache.type);
cache.refreshCache();
}
catch (Exception e) {
String subject = "Cache refresh failed in BMW";
LOG.log(Level.WARN, subject + ". Exception thrown:", e);
}
}
}
public void refreshCaches(List<cache> caches)
{
ThreadFactory ourThreadFactory =
new NamedThreadFactory("CacheHandler", true);
ScheduledExecutorService scheduleService =
Executors.newScheduledThreadPool(32, ourThreadFactory);
initialDelay = 60;
for (Cache cache : caches) {
service.scheduleWithFixedDelay(new CacheRefresher(cache), initialDelay, 20, TimeUnit.SECONDS);
initialDelay += 2;
cacheContainers.add(cache);
}
}
}
Is it possible that a thread is exceeding max heap limit and error is getting thrown but since I am not catching error I am not observing it?
But I am not sure if outofmemory error is thrown by one thread then will the entire application stop or only a thread will get impacted? Any comment?
Related
EDIT: It turns out that my docker container was closing because of an errant health check failing. This caused the kubernetes probe to fail too many times and killed the pod. Since the command came from outside the JVM, it is likely not possible for the code to know when the container around the JVM was killed. Leaving this question up in case someone finds an answer.
I have a Java SE project that reads in arguments to process files. I am using Weld-SE for injection. After a few minutes of running, the weld container shuts down mid progressing without explanation. The following is a skeleton of my code. Here in my Main Class
#ApplicationScoped
public class Main {
#Setter //Lombok annotation
private Scheduler scheduler;
public void schedule(String[] filenames) throws InterruptedException {
scheduler.schedule(filenames);
}
#PreDestroy
public void cleanUp() {
log.info("PreDestroy - Main");
//clean up omitted
}
public static void main(String[] args) {
Weld weld = new Weld();
Main main = null;
try (WeldContainer container = weld.initialize()) {
main = container.select(Main.class).get();
Scheduler scheduler = CDI.current().select(Scheduler.class).get();
main.setScheduler(scheduler);
main.schedule(args);
log.info("Main - completed processing");
} catch (Exception e) {
log.info("Exception occurred: " + e.getMessage(), e);
} finally {
log.info("Main Finally - Shutting down Weld");
CDI.current().destroy(main);
weld.shutdown();
}
}
}
Here is my Scheduler class
#Named
public class Scheduler {
private ThreadPoolExecutor executor;
private Map<Future<?>, Importer> beanMap = new HashMap<>();
private static final Duration sleepDuration = Duration.ofSeconds(45);
#PostConstructor
public void init() {
//setup executor
}
#PreDestroy
public void cleanUp() {
log.info("PreDestroy - Scheduler");
//clean up omitted
}
public void schedule(String[] filenames) throws InterruptedException {
for(String filename : filenames) {
Importer caller = CDI.current().select(Importer.class).get();
caller.setFilename(filename);
Future<?> future = executor.submit(caller);
beanMap.put(future, caller);
}
while(!isDone()) {
Thread.sleep(sleepDuration.toMillis());
log.info("Remaining threads: {}, getRemaining());
destroyCompleted();
}
}
//Returns true only when all threads are completed
private boolean isDone() { //code omitted }
//Returns number of not completed threads
private int getRemaining() { //code omitted }
//Clean up any completed Importers
private boolean destroyCompleted() { //code omitted }
}
Here is my Importer code
#Named
public class Importer implements Callable<String> {
#Setter //lombok annotation
private String filename;
public void cleanUp() {
log.info("PreDestroy - Importer");
//clean up omitted
}
public String call() {
List<String> content = //extract file content
for(int i = 0; i < content.size; i++) {
if (i+1 % 10000 == 0) {
log.info("Processed {} rows in file {}", i+1, filename);
}
//rest of loop omitted
}
}
}
The file test.txt has around 100,000 lines so I can tell that the crash happens mid file processing. So after my code runs for a few minutes I get the following at the end of my log
Processed 50000 rows in file test.txt
Processed 60000 rows in file text.txt
PreDestroy - Scheduler
PreDestroy - Importer
PreDestroy - Main
WELD-ENV-002001: Weld SE container 03128098-039d-46db-97e5-8538a52a38cc shut down
I am logging "org.jboss" at DEBUG level. I can see that the container was shutdown midway through processing a file, but I don't see why it occurred. Is there some type of listener that I can extend/implement to see why shut down command happened?
For future reference: You can define an observer method for the BeforeShutdown event which you can use to at least close all open files and such before shutdown. It won't necessarily give you a reason for why it's shutting down, but it's a start.
If you say the JVM process was terminated from outside, then there's probably an InterruptedException thrown somewhere which you can catch. Note that catching InterruptedException and not re-interrupting the thread is a bug most of the time. In your case, you should react to it with an orderly shutdown when calling Thread#sleep. If the thread gets interrupted, someone wants to cancel the execution. They probably have a good reason for doing so; don't think you know better than them!
At the very least you can periodically check the interrupt flag of your threads at some convenient point during execution to initiate an orderly shutdown of your task.
I am trying to change Quartz Sequential execution to Parallel Execution.
It is working fine, Performance wise, it is seems good but Spawned (created) threads are not destroyed.
It is Still in Runnable State; why and How can I fix that?
Please Guide me.
Code is here :
#Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.error("Result Processing executed");
List<Object[]> lstOfExams = examService.getExamEntriesForProcessingResults();
String timeZone = messageService.getMessage("org.default_timezone", null, Locale.getDefault());
if(lstOfExams!=null&&!lstOfExams.isEmpty()){
ThreadPoolTaskExecutor threadPoolExecuter = new ThreadPoolTaskExecutor();
threadPoolExecuter.setCorePoolSize(lstOfExams.size());
threadPoolExecuter.setMaxPoolSize(lstOfExams.size()+1);
threadPoolExecuter.setBeanName("ThreadPoolTaskExecutor");
threadPoolExecuter.setQueueCapacity(100);
threadPoolExecuter.setThreadNamePrefix("ThreadForUpdateExamResult");
threadPoolExecuter.initialize();
for(Object[] obj : lstOfExams){
if(StringUtils.isNotBlank((String)obj[2]) ){
timeZone = obj[2].toString();
}
try {
Userexams userexams=examService.findUserExamById(Long.valueOf(obj[0].toString()));
if(userexams.getExamresult()==null){
UpdateUserExamDataThread task=new UpdateUserExamDataThread(obj,timeZone);
threadPoolExecuter.submit(task);
}
// testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
// logger.error("Percentage Marks:::::"+result.getPercentageCatScore());
} catch (Exception e) {
Log.error("Exception at ResultProcessingJob extends QuartzJobBean executeInternal(JobExecutionContext context) throws JobExecutionException",e);
continue;
}
}
threadPoolExecuter.shutdown();
}
}
UpdateUserExamDataThread .class
#Component
//#Scope(value="prototype", proxyMode=ScopedProxyMode.TARGET_CLASS)
//public class UpdateUserExamDataThread extends ThreadLocal<String> //implements Runnable {
public class UpdateUserExamDataThread implements Runnable {
private Logger log = Logger.getLogger(UpdateUserExamDataThread.class);
#Autowired
ExamService examService;
#Autowired
TestEvaluator testEvaluator;
private Object[] obj;
private String timeZone;
public UpdateUserExamDataThread(Object[] obj,String timeZone) {
super();
this.obj = obj;
this.timeZone = timeZone;
}
#Override
public void run() {
String threadName=String.valueOf(obj[0]);
log.info("UpdateUserExamDataThread Start For:::::"+threadName);
testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
//update examResult
log.info("UpdateUserExamDataThread End For:::::"+threadName);
}
}
TestEvaluatorImpl.java
#Override
#Transactional
public Examresult generateTestResultAsPerEvaluator(Long userExamId, String evaluatorType, String codingLanguage,String timeZoneFollowed ,String inctenceId ,String userId) {
dbSchema = messageService.getMessage("database.default_schema", null, Locale.getDefault());
try {
//Some Methods
return examResult;
}catch(Exception e){
log.erorr(e);
}
}
I can provide Thread Dump file if needed.
it seems you create a thread pool in the same size of exams which is not quite optimal.
// Core pool size is = number of exams
threadPoolExecuter.setCorePoolSize(lstOfExams.size());
// Max pool size is just 1 + exam size.
threadPoolExecuter.setMaxPoolSize(lstOfExams.size()+1);
You have to consider that:
- If you create a thread pool and started it as many threads as defined in core size started immediately.
The max pool size is only than effective when you submit more than core pool threads can process right now AND when the queue size is full (in this case 100). So that means a new thread will be only then created when the number of submitted tasks exceeded 100+exam size.
In your case I would set the core pool size 5 or 10 (it actually depends on the how many core your target CPU have and/or how IO bound the submitted tasks are).
The max pool size can be double of that but it doesn't effective until the queue is full.
To let the size of live threads decrease after the submitted work done you have to set 2 parameters.
setKeepAliveSeconds(int keepAliveSeconds) : Which let the threads shut down automatically if they are not used along the defined seconds (by default 60 seconds, which is optimal) BUT this is normally only used to shut down threads of non-core pool threads.
To shut down threads of core part after keepAliveSeconds you have to set setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) as true. Which is normally false to keep core pool alive as long as the application is running.
I hope it helps.
I suspect that one of your threads waits indefinitely for an IO request answer. For example, you try to connect to a remote host where you did not set connection timeout and the host does not answer. In this case, you can shutdown all executing tasks forcefully by running shutdownNow method of the underlying ExecutorService then you can analyze InterruptedIOException thrown by the offending threads.
Replace
threadPoolExecuter.shutdown();
with below so you can examine errors.
ExecutorService executorService = threadPoolExecuter.getThreadPoolExecutor();
executorService.shutdownNow();
This will send interrupt signal to all running threads.
The threads do not wait on IO from some remote server, because the executed method on the threads would be in some jdbc driver classes, but they are currently all in UpdateUserExamDataThread.run(), line 37.
Now the question is: what is the code at UpdateUserExamDataThread.java line 37 ?
Unfortunately, the UpdateUserExamDataThread.java given at the moment is incomplete and/or not the version really executed: the package declaration is missing and it ends at line 29.
I suspect the issue is simply that you are calling run() instead of execute() when spawning the task thread using submit(). There is probably some expectation when using submit that threads kill themselves when the task is finished rather than terminating at the end of the run method.
Just Needed to increase the priority of threads and create number of threads as per number of cores in processor.
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.error("Result Processing executed");
List<Object[]> lstOfExams = examService.getExamEntriesForProcessingResults();
String timeZone = messageService.getMessage("org.default_timezone", null, Locale.getDefault());
int cores = Runtime.getRuntime().availableProcessors();
if(lstOfExams!=null&&!lstOfExams.isEmpty()){
ThreadPoolTaskExecutor threadPoolExecuter = new ThreadPoolTaskExecutor();
threadPoolExecuter.setCorePoolSize(cores);
// threadPoolExecuter.setMaxPoolSize(Integer.MAX_VALUE);
threadPoolExecuter.setBeanName("ThreadPoolTaskExecutor");
// threadPoolExecuter.setQueueCapacity(Integer.MAX_VALUE);
threadPoolExecuter.setQueueCapacity(lstOfExams.size()+10);
threadPoolExecuter.setThreadNamePrefix("ThreadForUpdateExamResult");
threadPoolExecuter.setWaitForTasksToCompleteOnShutdown(true);
threadPoolExecuter.setThreadPriority(10);
threadPoolExecuter.initialize();
for(Object[] obj : lstOfExams){
if(StringUtils.isNotBlank((String)obj[2]) ){
timeZone = obj[2].toString();
}
try {
Userexams userexam=examService.findUserExamById(Long.valueOf(obj[0].toString()));
if(userexam.getExamresult()==null){
UpdateUserExamDataThread task=new UpdateUserExamDataThread(obj,timeZone,testEvaluator);
// threadPoolExecuter.submit(task);
threadPoolExecuter.execute(task);
}
// testEvaluator.generateTestResultAsPerEvaluator(Long.valueOf(obj[0].toString()), obj[4].toString(), obj[3]==null?null:obj[3].toString(),timeZone ,obj[5].toString() ,obj[1].toString());
// logger.error("Percentage Marks:::::"+result.getPercentageCatScore());
} catch (Exception e) {
logger.error("Exception at ResultProcessingJob extends QuartzJobBean executeInternal(JobExecutionContext context) throws JobExecutionException",e);
continue;
}
}
threadPoolExecuter.shutdown();
}
}
Consider this simple program:
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
public class Main {
final static Logger logger = Logger.getLogger(Main.class.getName());
public static void main(String[] args) throws ExecutionException, InterruptedException {
final LoadingCache<Integer, String> cache = CacheBuilder.newBuilder().build(
new CacheLoader<Integer, String>() {
#Override
public String load(Integer arg0) throws Exception {
logger.info("Cache builder START: " + arg0);
Thread.sleep(4000);
logger.info("Cache builder FINISH: " + arg0);
return "This is what CacheBuilder returned for key " + arg0;
}
});
Thread getterThread = new Getter(cache);
getterThread.start();
Thread setterThread = new Setter(cache);
setterThread.start();
getterThread.join();
setterThread.join();
logger.info("Finally in cache we have: " + cache.get(1));
}
private static final class Getter extends Thread {
private final LoadingCache<Integer, String> cache;
private Getter(LoadingCache<Integer, String> cache) {
this.cache = cache;
}
#Override
public void run() {
try {
logger.info("Getter thread reads 1st time " + cache.get(1)
+ " <<<<<<<<<< WHAT !?!");
// allow the setter to put the value
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("Getter thread reads 2nd time " + cache.get(1));
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
private static final class Setter extends Thread {
private final LoadingCache<Integer, String> cache;
private Setter(LoadingCache<Integer, String> cache) {
this.cache = cache;
}
#Override
public void run() {
try {
// deliberately wait to allow the Getter thread
// trigger cache loading
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
cache.put(1, "This isn't where I parked my car!");
logger.info("Setter thread now reads: " + cache.get(1));
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
And the output is:
2013-11-08 15:24:32 INFO Main$1 load Cache builder START: 1
2013-11-08 15:24:32 INFO Main$Setter run Setter thread now reads: This isn't where I parked my car!
2013-11-08 15:24:36 INFO Main$1 load Cache builder FINISH: 1
2013-11-08 15:24:36 INFO Main$Getter run Getter thread reads 1st time This is what CacheBuilder returned for key 1 <<<<<<<<<< WHAT !?!
2013-11-08 15:24:37 INFO Main$Getter run Getter thread reads 2nd time This isn't where I parked my car!
2013-11-08 15:24:37 INFO Main main Finally in cache we have: This isn't where I parked my car!
I'm getting this "This is what CacheBuilder returned for key 1" in Getter thread.
Obviously this is because the get(1) called by Getter triggers cache loading, but meanwhile the Setter thread comes and puts some other value for key 1.
I'd expect it to return the same what was just put before by Setter = "This isn't where I parked my car!" (which I get the 2nd time Getter retrieves value for 1).
Did I miss something ?
Thanks in advance
Yes. The internal data structures of the cache are synchronized to protect you against pollution like that. The model in your head should be: As long as a thread is using the cache, it has its own copy.
So the first thread triggers the cache loading. Guava "clones" the cache (internally, it just makes sure no one can change the structures thread 1 is seeing). After 4 seconds, the thread gets the result returned by the cache loading, no matter how many other threads change the value in the mean time (they all get their own "copy" to modify).
When thread 1 is finished, the cache updates itself. Now the change from thread 2 becomes visible for thread 1.
I'm new to the #Schedule annotations in J2EE6
I want to run a job using EJB 3.x with Glassfish 3.1.
The javax.ejb.Schedule seems to be a good choice for us, so we could think of our custom time as something like:
#Singleton
public class CustomTimer {
#EJB
SettingsFacade settingsFacade;
#Schedule(second="someSecondParameter", minute="someMinuteParameter",hour="someHourParameter", persistent=false)
public void executeTimer(){
//Code executing something against database using the settingsFacade
}
}
Here, we want the parameters to be got from database, so they are changed every month. Any clean solution for this?
#Singleton
#Startup
public class ScheduleTimerService {
#Resource private TimerService timerService;
public void setTimerService(TimerService timerService) {this.timerService = timerService; }
#PostConstruct
private void postConstruct() {
timerService.createCalendarTimer(createSchedule());
}
#Timeout
public void timerTimeout(Timer timer) {
Add your code here to be called when scheduling is reached...
in this example: 01h:30m every day ;-)
}
private ScheduleExpression createSchedule(){
ScheduleExpression expression = new ScheduleExpression();
expression.dayOfWeek("Sun,Mon,Tue,Wed,Thu,Fri,Sat");
expression.hour("01");
expression.minute("30");
return expression;
}
}
No, there is no solution with #Schedule, because annotation attributes in general should be compile time constants.
When more flexibility is needed, programmatic timers can be used.
Also then polling database for changed configuration and removing existing and creating new timers must be implemented.
Well You need to created Two Scheduler
One Scheduler will run to update data from Database
Based On that You Can created Other Scheduler.
But for this Need to do it some what programmatic.
You also can see EJB Timers for the same what will help you in this case. which is also annotation based.
There is a simple way of doing this. I wanted to something that called a process every day but, the job itself should be done randomly over the same day. I managed to do that by adding a simple thread worker to run after the EJB timer service has been called. Then I would put it to sleep for a random amount of time during that day.
The following code is an example of a service that wakes up every 1 minute and waits for a thread to finish.
#Schedule(minute = "*/1", hour = "*", persistent = false)
public void runEveryMinute() throws InterruptedException {
log.log(Level.INFO, "Scheduling for every minute .. now it's: " + new Date().toString());
// Delay, in milliseconds before we interrupt adding a follower thread
//we can therefore garantee that it runs every day
long patience = 1000 * 5;
threadMessage("Starting forever alone no more thread");
long startTime = System.currentTimeMillis();
Thread t = new Thread(new MessageLoop());
t.start();
threadMessage("Waiting for new thread to finish");
// loop until MessageLoop thread exits
while (t.isAlive()) {
threadMessage("Still waiting...");
// Wait maximum of 1 second for MessageLoop thread to finish.
t.join(1000);
if (((System.currentTimeMillis() - startTime) > patience)
&& t.isAlive()) {
threadMessage("Tired of waiting! Adding new followers now!");
t.interrupt();
// Shouldn't be long now -- wait indefinitely
t.join();
}
}
threadMessage("Finally! You are not alone anymore!");
}
// Display a message, preceded by
// the name of the current thread
static void threadMessage(String message) {
String threadName = Thread.currentThread().getName();
System.out.format("%s: %s%n", threadName, message);
}
private static class MessageLoop implements Runnable {
public void run() {
String importantInfo[] = {
"A kid will eat ivy too"
};
try {
for (int i = 0;
i < importantInfo.length;
i++) {
// Pause for 4 seconds
int max = 10;
int min = 2;
int randomTimer = 0 + (int) (Math.random() * ((max - min) + 1));
Thread.sleep(randomTimer * 1000);
// Print a message
threadMessage(importantInfo[i]);
}
} catch (InterruptedException e) {
threadMessage("Patience is not a virtue! Thread stopping for now!");
}
}
}
I'm trying to find more information on how to bound the running time of a task created using ThreadPoolExecutor.
I want to create a self destructing, e.g. when time has passed (1m for example) then the thread will terminate itself automatically and return a null value. The key point here is that waiting for the thread to finish should not block the main thread (UI thread in our example).
I know I can use the get method, however it will block my application.
I was thinking about running an additional internal thread that will sleep for 1m and then will call interrupt on the main thread.
I attached an example code, it looks like a good idea, but I need another pair of eyes telling me if it makes sense.
public abstract class AbstractTask<T> implements Callable<T> {
private final class StopRunningThread implements Runnable {
/**
* Holds the main thread to interrupt. Cannot be null.
*/
private final Thread mMain;
public StopRunningThread(final Thread main) {
mMain = main;
}
#Override
public void run() {
try {
Thread.sleep(60 * 1000);
// Stop it.
mMain.interrupt();
} catch (final InterruptedException exception) {
// Ignore.
}
}
}
call() is called via a ThreadPool
public T call() {
try {
// Before running any task initialize the result so that the user
// won't
// think he/she has something.
mResult = null;
mException = null;
// Stop running thread.
mStopThread = new Thread(new StopRunningThread(
Thread.currentThread()));
mStopThread.start();
mResult = execute(); <-- A subclass implements this one
} catch (final Exception e) {
// An error occurred, ignore any result.
mResult = null;
mException = e;
// Log it.
Ln.e(e);
}
// In case it's out of memory do a special catch.
catch (final OutOfMemoryError e) {
// An error occurred, ignore any result.
mResult = null;
mException = new UncheckedException(e);
// Log it.
Ln.e(e);
} finally {
// Stop counting.
mStopThread.interrupt();
}
return mResult;
}
There are couple of points which I'm afraid of:
What will happen if execute() has an exception and immediately afterwards my external thread will interrupt, then I'll never catch the exception.
Memory/CPU consumption, I am using a thread pool to avoid the creation of new threads.
Do you see a better idea for reaching the same functionality ?
Doing this would be somewhat involved. First, you'd need to extend the ThreadPoolExecutor class. You'll need to override the "beforeExecute" and "afterExecute" methods. They would keep track of thread start times, and do cleanup after. Then you'd need a reaper to periodically check to see which threads need cleaning up.
This example uses a Map to record when each thread is started. The beforeExecute method populates this, and the afterExecute method cleans it up. There is a TimerTask which periodically executes and looks at all the current entries (ie. all the running threads), and calls Thread.interrupt() on all of them that have exceeded the given time limit.
Notice that I have given two extra constructor parameters: maxExecutionTime, and reaperInterval to control how long tasks are given, and how often to check for tasks to kill. I've omitted some constructors here for the the sake of brevity.
Keep in mind the tasks you submit have to play nice and allow themselves to be killed. This means you have to:
Check Thread.currentThread().isInterrupted() at regular intervals
during execution.
Try to avoid any blocking operation that does not declare
InterruptedException in it's throws clause. A prime example of this
would be InputStream/OutputStream usage, and you would use NIO
Channels instead. If you have to use these methods, check the interrupted flag immediately after returning from such an operation.
.
public class TimedThreadPoolExecutor extends ThreadPoolExecutor {
private Map<Thread, Long> threads = new HashMap<Thread, Long>();
private Timer timer;
public TimedThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,
long maxExecutionTime,
long reaperInterval) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
startReaper(maxExecutionTime, reaperInterval);
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
threads.remove(Thread.currentThread());
System.out.println("after: " + Thread.currentThread().getName());
super.afterExecute(r, t);
}
#Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
System.out.println("before: " + t.getName());
threads.put(t, System.currentTimeMillis());
}
#Override
protected void terminated() {
if (timer != null) {
timer.cancel();
}
super.terminated();
}
private void startReaper(final long maxExecutionTime, long reaperInterval) {
timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
// make a copy to avoid concurrency issues.
List<Map.Entry<Thread, Long>> entries =
new ArrayList<Map.Entry<Thread, Long>>(threads.entrySet());
for (Map.Entry<Thread, Long> entry : entries) {
Thread thread = entry.getKey();
long start = entry.getValue();
if (System.currentTimeMillis() - start > maxExecutionTime) {
System.out.println("interrupting thread : " + thread.getName());
thread.interrupt();
}
}
}
};
timer.schedule(timerTask, reaperInterval, reaperInterval);
}
public static void main(String args[]) throws Exception {
TimedThreadPoolExecutor executor = new TimedThreadPoolExecutor(5,5, 1000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(20),
1000L,
200L);
for (int i=0;i<10;i++) {
executor.execute(new Runnable() {
public void run() {
try {
Thread.sleep(5000L);
}
catch (InterruptedException e) {
}
}
});
}
executor.shutdown();
while (! executor.isTerminated()) {
executor.awaitTermination(1000L, TimeUnit.MILLISECONDS);
}
}
}