diff --git a/bin/jmeter.properties b/bin/jmeter.properties
index 58c540cfd9c..f75f3136f8f 100644
--- a/bin/jmeter.properties
+++ b/bin/jmeter.properties
@@ -1174,6 +1174,9 @@ cookies=cookies
# How often to check for shutdown during ramp-up (milliseconds)
#jmeterthread.rampup.granularity=1000
+# How often to check for shutdown during timer delay (milliseconds)
+#jmeterthread.timer.granularity=1000
+
#Should JMeter expand the tree when loading a test plan?
# default value is false since JMeter 2.7
#onload.expandtree=false
diff --git a/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java b/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java
index 35f94b26982..c6498ba8cd5 100644
--- a/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java
+++ b/src/core/src/main/java/org/apache/jmeter/threads/JMeterThread.java
@@ -80,6 +80,10 @@ public class JMeterThread implements Runnable, Interruptible {
private static final int RAMPUP_GRANULARITY =
JMeterUtils.getPropDefault("jmeterthread.rampup.granularity", 1000); // $NON-NLS-1$
+ /** How often to check for shutdown during timer delay, default 1000ms */
+ private static final int TIMER_GRANULARITY =
+ JMeterUtils.getPropDefault("jmeterthread.timer.granularity", 1000); // $NON-NLS-1$
+
private static final float TIMER_FACTOR = JMeterUtils.getPropDefault("timer.factor", 1.0f);
private static final TimerService TIMER_SERVICE = TimerService.getInstance();
@@ -998,21 +1002,36 @@ private void delay(List extends Timer> timers) {
totalDelay += delay;
}
if (totalDelay > 0) {
- try {
- if (scheduler) {
- // We reduce pause to ensure end of test is not delayed by a sleep ending after test scheduled end
- // See Bug 60049
- totalDelay = TIMER_SERVICE.adjustDelay(totalDelay, endTime, false);
- if (totalDelay < 0) {
- log.debug("The delay would be longer than the scheduled period, so stop thread now.");
- running = false;
- return;
+ if (scheduler) {
+ // We reduce pause to ensure end of test is not delayed by a sleep ending after test scheduled end
+ // See Bug 60049
+ totalDelay = TIMER_SERVICE.adjustDelay(totalDelay, endTime, false);
+ if (totalDelay < 0) {
+ log.debug("The delay would be longer than the scheduled period, so stop thread now.");
+ running = false;
+ return;
+ }
+ }
+ // Use granular sleeps to allow quick response to shutdown
+ long start = System.currentTimeMillis();
+ long end = start + totalDelay;
+ long now;
+ long pause = TIMER_GRANULARITY;
+ while (running && (now = System.currentTimeMillis()) < end) {
+ long togo = end - now;
+ if (togo < pause) {
+ pause = togo;
+ }
+ try {
+ TimeUnit.MILLISECONDS.sleep(pause);
+ } catch (InterruptedException e) {
+ if (running) { // NOSONAR running may have been changed from another thread
+ log.warn("The delay timer was interrupted - Loss of delay for {} was {}ms out of {}ms",
+ threadName, System.currentTimeMillis() - start, totalDelay);
}
+ Thread.currentThread().interrupt();
+ break;
}
- TimeUnit.MILLISECONDS.sleep(totalDelay);
- } catch (InterruptedException e) {
- log.warn("The delay timer was interrupted - probably did not wait as long as intended.");
- Thread.currentThread().interrupt();
}
}
}
diff --git a/xdocs/usermanual/properties_reference.xml b/xdocs/usermanual/properties_reference.xml
index a40ae5027a6..995daf94a6e 100644
--- a/xdocs/usermanual/properties_reference.xml
+++ b/xdocs/usermanual/properties_reference.xml
@@ -1484,6 +1484,10 @@ JMETER-SERVER
How often to check for shutdown during ramp-up (milliseconds).
Defaults to: 1000
+
+ How often to check for shutdown during timer delay (milliseconds).
+ Defaults to: 1000
+
Should JMeter expand the tree when loading a test plan?
Default value is false since JMeter 2.7