Concurrent package was introduced from Java 5 and still doesn't get reasonable acceptance. Traditional thread programming is just too strong for us to unlearn it. Several years ago, I created a task framework to solve commonly used scenario, a modified version (most changes are generic related) is used in a product I participated in 2008.
In my current project, I have a requirement of setting timeout for serials of web service operations, which is very suitable for concurrent package. I learned a good lesson from this simple task. I reckon I need to revise my framework one day.
The 1st lesson I learned is it's harder and not safe to set thread name to a Callable thread. One workaround is calling Thread.currentThread().setName() at the beginning of call(). But thread is not owned by Callable but by ExecutorService, so this might have some side-effects. Use it at your own risk.
The 2nd one is the overhead of creating and removing threads is much heavier than I imaged before. In debug mode you can see the process of creation and removal of threads, especially when you submit the thread in loops. Try your best to minimize the operations in call() and only call call() when necessary.
Third tip is by using Future.get(1L, TimeUnit.MILLISECONDS) and ignoring TimeoutException you get an asynchronized thread.
Last but not least is always cancel future and shutdown service. If you fail to do so, the callable will be in running status forever and eventually you'll have no memory to create any new thread. Although I don't see any difference between Future.cancel(true) and Future.cancel(false), ExecutorService.shutdown() and ExecutorService.shutdownNow() in my case.