1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.osgi.extender.internal.util.concurrent;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.springframework.beans.factory.DisposableBean;
22 import org.springframework.core.task.TaskExecutor;
23 import org.springframework.util.Assert;
24
25 /**
26 * Utility class that executes the given Runnable task on the given task
27 * executor or , if none is given, to a new thread.
28 *
29 * <p/> If the thread does not return in the given amount of time, it will be
30 * interrupted and a logging message sent.
31 *
32 * <p/> This class is intended for usage inside the framework, mainly by the
33 * extender package for controlling runaway threads.
34 *
35 * @see Counter
36 * @see Thread
37 * @author Costin Leau
38 *
39 */
40 public abstract class RunnableTimedExecution {
41
42 /** logger */
43 private static final Log log = LogFactory.getLog(RunnableTimedExecution.class);
44
45
46 private static class MonitoredRunnable implements Runnable {
47
48 private Runnable task;
49
50 private Counter counter;
51
52
53 public MonitoredRunnable(Runnable task, Counter counter) {
54 this.task = task;
55 this.counter = counter;
56 }
57
58 public void run() {
59 try {
60 task.run();
61 }
62 finally {
63 counter.decrement();
64 }
65 }
66 }
67
68 private static class SimpleTaskExecutor implements TaskExecutor, DisposableBean {
69
70 private Thread thread;
71
72
73 public void execute(Runnable task) {
74 thread = new Thread(task);
75 thread.setName("Thread for runnable [" + task + "]");
76 thread.start();
77 }
78
79 public void destroy() throws Exception {
80 if (thread != null) {
81 thread.interrupt();
82 }
83 }
84 }
85
86
87 public static boolean execute(Runnable task, long waitTime) {
88 return execute(task, waitTime, null);
89 }
90
91 public static boolean execute(Runnable task, long waitTime, TaskExecutor taskExecutor) {
92 Assert.notNull(task);
93
94 Counter counter = new Counter("counter for task: " + task);
95 Runnable wrapper = new MonitoredRunnable(task, counter);
96
97 boolean internallyManaged = false;
98
99 if (taskExecutor == null) {
100 taskExecutor = new SimpleTaskExecutor();
101 internallyManaged = true;
102 }
103
104 counter.increment();
105
106 taskExecutor.execute(wrapper);
107
108 if (counter.waitForZero(waitTime)) {
109 log.error(task + " did not finish in " + waitTime
110 + "ms; consider taking a snapshot and then shutdown the VM in case the thread still hangs");
111
112 if (internallyManaged) {
113 try {
114 ((DisposableBean) taskExecutor).destroy();
115 }
116 catch (Exception e) {
117
118 }
119 }
120 return true;
121 }
122
123 return false;
124 }
125 }