0
# Task Execution
1
2
Spring Core provides a comprehensive task execution framework that abstracts thread management and provides both synchronous and asynchronous task execution capabilities. This system supports everything from simple thread pools to modern virtual thread implementations.
3
4
## Core Task Executor Interfaces
5
6
The task execution system is built around a hierarchy of interfaces that provide increasingly sophisticated execution capabilities.
7
8
**TaskExecutor Interface**
9
```java { .api }
10
@FunctionalInterface
11
public interface TaskExecutor extends Executor {
12
void execute(Runnable task);
13
}
14
15
public interface AsyncTaskExecutor extends TaskExecutor {
16
long TIMEOUT_UNLIMITED = Long.MAX_VALUE;
17
long TIMEOUT_IMMEDIATE = 0;
18
19
void execute(Runnable task, long startTimeout);
20
Future<?> submit(Runnable task);
21
<T> Future<T> submit(Callable<T> task);
22
}
23
24
public interface SchedulingTaskExecutor extends AsyncTaskExecutor {
25
boolean prefersShortLivedTasks();
26
}
27
```
28
29
**Task Decorator Interface**
30
```java { .api }
31
@FunctionalInterface
32
public interface TaskDecorator {
33
Runnable decorate(Runnable runnable);
34
}
35
```
36
37
**Usage Examples**
38
```java
39
// Basic task execution
40
TaskExecutor executor = new SimpleAsyncTaskExecutor();
41
42
// Execute fire-and-forget tasks
43
executor.execute(() -> {
44
System.out.println("Task executed in: " + Thread.currentThread().getName());
45
});
46
47
// Asynchronous execution with results
48
AsyncTaskExecutor asyncExecutor = new SimpleAsyncTaskExecutor();
49
50
// Submit runnable task
51
Future<?> future1 = asyncExecutor.submit(() -> {
52
// Long running task
53
processLargeDataset();
54
});
55
56
// Submit callable task
57
Future<String> future2 = asyncExecutor.submit(() -> {
58
return fetchDataFromRemoteService();
59
});
60
61
// Wait for results
62
try {
63
future1.get(5, TimeUnit.SECONDS);
64
String result = future2.get(10, TimeUnit.SECONDS);
65
} catch (TimeoutException ex) {
66
// Handle timeout
67
}
68
69
// Task decoration
70
TaskDecorator decorator = task -> {
71
return () -> {
72
String originalName = Thread.currentThread().getName();
73
Thread.currentThread().setName("CustomTask-" + originalName);
74
try {
75
task.run();
76
} finally {
77
Thread.currentThread().setName(originalName);
78
}
79
};
80
};
81
82
// Apply decorator to executor (implementation-dependent)
83
```
84
85
## Task Executor Implementations
86
87
Spring provides several built-in task executor implementations for different use cases.
88
89
**SimpleAsyncTaskExecutor**
90
```java { .api }
91
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
92
implements AsyncTaskExecutor, Serializable {
93
94
public static final int UNBOUNDED_CONCURRENCY = -1;
95
public static final int NO_CONCURRENCY = 0;
96
97
public SimpleAsyncTaskExecutor();
98
public SimpleAsyncTaskExecutor(String threadNamePrefix);
99
public SimpleAsyncTaskExecutor(ThreadFactory threadFactory);
100
101
public void setConcurrencyLimit(int concurrencyLimit);
102
public int getConcurrencyLimit();
103
public boolean isThrottleActive();
104
105
public void setTaskDecorator(TaskDecorator taskDecorator);
106
107
@Override
108
public void execute(Runnable task);
109
@Override
110
public void execute(Runnable task, long startTimeout);
111
@Override
112
public Future<?> submit(Runnable task);
113
@Override
114
public <T> Future<T> submit(Callable<T> task);
115
116
protected void doExecute(Runnable task);
117
protected Thread createThread(Runnable runnable);
118
}
119
```
120
121
**SyncTaskExecutor**
122
```java { .api }
123
public class SyncTaskExecutor implements TaskExecutor, Serializable {
124
@Override
125
public void execute(Runnable task);
126
}
127
```
128
129
**VirtualThreadTaskExecutor (Java 21+)**
130
```java { .api }
131
public class VirtualThreadTaskExecutor implements AsyncTaskExecutor, Serializable {
132
public VirtualThreadTaskExecutor();
133
public VirtualThreadTaskExecutor(String threadNamePrefix);
134
135
public void setThreadNamePrefix(String threadNamePrefix);
136
public String getThreadNamePrefix();
137
138
public void setTaskDecorator(TaskDecorator taskDecorator);
139
public TaskDecorator getTaskDecorator();
140
141
@Override
142
public void execute(Runnable task);
143
@Override
144
public Future<?> submit(Runnable task);
145
@Override
146
public <T> Future<T> submit(Callable<T> task);
147
148
@Override
149
public void execute(Runnable task, long startTimeout);
150
151
protected Thread createVirtualThread(Runnable runnable);
152
}
153
```
154
155
**Usage Examples**
156
```java
157
// Simple async task executor with concurrency control
158
SimpleAsyncTaskExecutor simpleExecutor = new SimpleAsyncTaskExecutor("MyApp-");
159
simpleExecutor.setConcurrencyLimit(10); // Limit to 10 concurrent threads
160
simpleExecutor.setTaskDecorator(task -> {
161
return () -> {
162
long start = System.currentTimeMillis();
163
try {
164
task.run();
165
} finally {
166
long duration = System.currentTimeMillis() - start;
167
System.out.println("Task completed in " + duration + "ms");
168
}
169
};
170
});
171
172
// Execute multiple tasks
173
for (int i = 0; i < 20; i++) {
174
final int taskId = i;
175
simpleExecutor.execute(() -> {
176
System.out.println("Executing task " + taskId +
177
" in thread " + Thread.currentThread().getName());
178
// Simulate work
179
try { Thread.sleep(1000); } catch (InterruptedException e) {}
180
});
181
}
182
183
// Synchronous executor (for testing or single-threaded contexts)
184
TaskExecutor syncExecutor = new SyncTaskExecutor();
185
syncExecutor.execute(() -> {
186
// This will execute in the calling thread
187
System.out.println("Sync execution in: " + Thread.currentThread().getName());
188
});
189
190
// Virtual thread executor (Java 21+)
191
VirtualThreadTaskExecutor virtualExecutor = new VirtualThreadTaskExecutor("VirtualTask-");
192
virtualExecutor.setTaskDecorator(task -> () -> {
193
System.out.println("Virtual thread: " + Thread.currentThread());
194
task.run();
195
});
196
197
// Virtual threads are ideal for I/O-bound tasks
198
List<Future<String>> futures = new ArrayList<>();
199
for (int i = 0; i < 10000; i++) { // Can handle thousands of virtual threads
200
Future<String> future = virtualExecutor.submit(() -> {
201
// Simulate I/O operation
202
Thread.sleep(Duration.ofSeconds(1));
203
return "Result from virtual thread";
204
});
205
futures.add(future);
206
}
207
208
// Collect results
209
List<String> results = futures.stream()
210
.map(future -> {
211
try { return future.get(); }
212
catch (Exception e) { return "Error"; }
213
})
214
.collect(Collectors.toList());
215
```
216
217
## Thread Pool Task Executor Support
218
219
While the core module doesn't include full thread pool implementations, it provides the foundation interfaces that are used by Spring's thread pool executors in other modules.
220
221
**Lifecycle Management**
222
```java { .api }
223
public interface DisposableBean {
224
void destroy() throws Exception;
225
}
226
227
public interface InitializingBean {
228
void afterPropertiesSet() throws Exception;
229
}
230
231
// Task executors often implement these for proper lifecycle management
232
public interface TaskExecutorConfiguration {
233
void initialize();
234
void shutdown();
235
boolean awaitTermination(long timeout, TimeUnit unit);
236
}
237
```
238
239
**Usage Examples**
240
```java
241
// Custom task executor with lifecycle management
242
public class ManagedTaskExecutor implements AsyncTaskExecutor, InitializingBean, DisposableBean {
243
private ExecutorService executor;
244
private final String threadNamePrefix;
245
private TaskDecorator taskDecorator;
246
247
public ManagedTaskExecutor(String threadNamePrefix) {
248
this.threadNamePrefix = threadNamePrefix;
249
}
250
251
@Override
252
public void afterPropertiesSet() {
253
ThreadFactory threadFactory = new CustomizableThreadFactory(threadNamePrefix);
254
this.executor = Executors.newCachedThreadPool(threadFactory);
255
}
256
257
@Override
258
public void destroy() throws Exception {
259
if (executor != null) {
260
executor.shutdown();
261
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
262
executor.shutdownNow();
263
}
264
}
265
}
266
267
@Override
268
public void execute(Runnable task) {
269
Runnable decoratedTask = (taskDecorator != null) ? taskDecorator.decorate(task) : task;
270
executor.execute(decoratedTask);
271
}
272
273
@Override
274
public Future<?> submit(Runnable task) {
275
Runnable decoratedTask = (taskDecorator != null) ? taskDecorator.decorate(task) : task;
276
return executor.submit(decoratedTask);
277
}
278
279
@Override
280
public <T> Future<T> submit(Callable<T> task) {
281
return executor.submit(task);
282
}
283
284
public void setTaskDecorator(TaskDecorator taskDecorator) {
285
this.taskDecorator = taskDecorator;
286
}
287
}
288
289
// Usage with Spring lifecycle
290
ManagedTaskExecutor managedExecutor = new ManagedTaskExecutor("Managed-");
291
managedExecutor.setTaskDecorator(task -> {
292
return () -> {
293
MDC.put("taskId", UUID.randomUUID().toString());
294
try {
295
task.run();
296
} finally {
297
MDC.clear();
298
}
299
};
300
});
301
302
managedExecutor.afterPropertiesSet(); // Initialize
303
304
// Use the executor
305
Future<String> result = managedExecutor.submit(() -> {
306
// Task execution with proper logging context
307
return "Task completed";
308
});
309
310
// Cleanup
311
managedExecutor.destroy();
312
```
313
314
## Task Execution Utilities
315
316
**CustomizableThreadCreator**
317
```java { .api }
318
public class CustomizableThreadCreator implements Serializable {
319
public static final String DEFAULT_THREAD_NAME_PREFIX =
320
ClassUtils.getShortName(CustomizableThreadCreator.class) + "-";
321
322
private String threadNamePrefix = DEFAULT_THREAD_NAME_PREFIX;
323
private int threadPriority = Thread.NORM_PRIORITY;
324
private boolean daemon = false;
325
private ThreadGroup threadGroup;
326
private Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
327
328
public CustomizableThreadCreator();
329
public CustomizableThreadCreator(String threadNamePrefix);
330
331
public void setThreadNamePrefix(String threadNamePrefix);
332
public String getThreadNamePrefix();
333
334
public void setThreadPriority(int threadPriority);
335
public int getThreadPriority();
336
337
public void setDaemon(boolean daemon);
338
public boolean isDaemon();
339
340
public void setThreadGroupName(String name);
341
public void setThreadGroup(ThreadGroup threadGroup);
342
public ThreadGroup getThreadGroup();
343
344
public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler uncaughtExceptionHandler);
345
public Thread.UncaughtExceptionHandler getUncaughtExceptionHandler();
346
347
public Thread createThread(Runnable runnable);
348
protected String nextThreadName();
349
public String getDefaultThreadNamePrefix();
350
}
351
```
352
353
**Usage Examples**
354
```java
355
// Customizable thread creation
356
CustomizableThreadCreator threadCreator = new CustomizableThreadCreator("WorkerPool-");
357
threadCreator.setThreadPriority(Thread.MAX_PRIORITY);
358
threadCreator.setDaemon(true);
359
threadCreator.setUncaughtExceptionHandler((thread, ex) -> {
360
System.err.println("Uncaught exception in thread " + thread.getName() + ": " + ex);
361
});
362
363
// Create custom threads
364
Thread workerThread = threadCreator.createThread(() -> {
365
// Worker task implementation
366
performWork();
367
});
368
369
workerThread.start();
370
371
// Use with task executors
372
public class CustomThreadTaskExecutor extends SimpleAsyncTaskExecutor {
373
public CustomThreadTaskExecutor() {
374
super("CustomTask-");
375
setThreadPriority(Thread.HIGH_PRIORITY);
376
setDaemon(false);
377
}
378
379
@Override
380
protected Thread createThread(Runnable runnable) {
381
Thread thread = super.createThread(runnable);
382
thread.setUncaughtExceptionHandler((t, e) -> {
383
// Custom exception handling
384
handleTaskException(t, e);
385
});
386
return thread;
387
}
388
389
private void handleTaskException(Thread thread, Throwable exception) {
390
// Log exception, notify monitoring system, etc.
391
}
392
}
393
```
394
395
## Asynchronous Method Support Foundation
396
397
While async method execution is handled in Spring Context, the core module provides the foundational interfaces.
398
399
**Future Result Handling**
400
```java { .api }
401
// Standard JDK interfaces that task executors work with
402
public interface Future<V> {
403
boolean cancel(boolean mayInterruptIfRunning);
404
boolean isCancelled();
405
boolean isDone();
406
V get() throws InterruptedException, ExecutionException;
407
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
408
}
409
410
public interface Callable<V> {
411
V call() throws Exception;
412
}
413
414
// Spring's ListenableFuture (from spring-context) extends this foundation
415
```
416
417
**Usage Examples**
418
```java
419
// Working with Future results
420
AsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
421
422
// Submit tasks and handle results
423
Future<Integer> calculation = executor.submit(() -> {
424
// Expensive calculation
425
Thread.sleep(2000);
426
return 42;
427
});
428
429
Future<String> dataFetch = executor.submit(() -> {
430
// Data fetching operation
431
return fetchFromDatabase();
432
});
433
434
// Non-blocking check
435
if (calculation.isDone()) {
436
try {
437
Integer result = calculation.get();
438
System.out.println("Calculation result: " + result);
439
} catch (ExecutionException ex) {
440
System.err.println("Calculation failed: " + ex.getCause());
441
}
442
}
443
444
// Blocking wait with timeout
445
try {
446
String data = dataFetch.get(5, TimeUnit.SECONDS);
447
processData(data);
448
} catch (TimeoutException ex) {
449
System.err.println("Data fetch timed out");
450
dataFetch.cancel(true);
451
} catch (ExecutionException ex) {
452
System.err.println("Data fetch failed: " + ex.getCause());
453
}
454
455
// Batch processing with CompletableFuture composition
456
List<Future<String>> futures = IntStream.range(0, 10)
457
.mapToObj(i -> executor.submit(() -> processItem(i)))
458
.collect(Collectors.toList());
459
460
// Wait for all to complete
461
List<String> results = futures.stream()
462
.map(future -> {
463
try {
464
return future.get(30, TimeUnit.SECONDS);
465
} catch (Exception ex) {
466
return "Error: " + ex.getMessage();
467
}
468
})
469
.collect(Collectors.toList());
470
```
471
472
## Task Execution Patterns
473
474
**Common Patterns and Best Practices**
475
```java
476
// Pattern 1: Fire-and-forget tasks
477
public class NotificationService {
478
private final TaskExecutor taskExecutor;
479
480
public NotificationService(TaskExecutor taskExecutor) {
481
this.taskExecutor = taskExecutor;
482
}
483
484
public void sendNotification(String message, String recipient) {
485
taskExecutor.execute(() -> {
486
// Send email/SMS notification asynchronously
487
emailService.send(recipient, message);
488
});
489
}
490
}
491
492
// Pattern 2: Producer-consumer with task decoration
493
public class AuditedTaskExecutor implements TaskExecutor {
494
private final TaskExecutor delegate;
495
private final AuditService auditService;
496
497
public AuditedTaskExecutor(TaskExecutor delegate, AuditService auditService) {
498
this.delegate = delegate;
499
this.auditService = auditService;
500
}
501
502
@Override
503
public void execute(Runnable task) {
504
String taskId = UUID.randomUUID().toString();
505
Runnable auditedTask = () -> {
506
auditService.logTaskStart(taskId);
507
long startTime = System.currentTimeMillis();
508
try {
509
task.run();
510
auditService.logTaskSuccess(taskId, System.currentTimeMillis() - startTime);
511
} catch (Exception ex) {
512
auditService.logTaskFailure(taskId, ex);
513
throw ex;
514
}
515
};
516
delegate.execute(auditedTask);
517
}
518
}
519
520
// Pattern 3: Graceful shutdown
521
public class GracefulTaskExecutor implements AsyncTaskExecutor, DisposableBean {
522
private final AsyncTaskExecutor delegate;
523
private final List<Future<?>> activeTasks = Collections.synchronizedList(new ArrayList<>());
524
private volatile boolean shutdownRequested = false;
525
526
public GracefulTaskExecutor(AsyncTaskExecutor delegate) {
527
this.delegate = delegate;
528
}
529
530
@Override
531
public Future<?> submit(Runnable task) {
532
if (shutdownRequested) {
533
throw new IllegalStateException("Executor is shutting down");
534
}
535
536
Future<?> future = delegate.submit(() -> {
537
try {
538
task.run();
539
} finally {
540
activeTasks.removeIf(f -> f.isDone() || f.isCancelled());
541
}
542
});
543
544
activeTasks.add(future);
545
return future;
546
}
547
548
@Override
549
public void destroy() throws Exception {
550
shutdownRequested = true;
551
552
// Wait for active tasks to complete
553
long deadline = System.currentTimeMillis() + 30000; // 30 second timeout
554
while (!activeTasks.isEmpty() && System.currentTimeMillis() < deadline) {
555
Thread.sleep(100);
556
activeTasks.removeIf(f -> f.isDone() || f.isCancelled());
557
}
558
559
// Cancel remaining tasks
560
activeTasks.forEach(future -> future.cancel(true));
561
}
562
}
563
```
564
565
This task execution framework provides the foundation for Spring's asynchronous processing capabilities, enabling developers to build scalable, non-blocking applications with proper resource management and lifecycle control.