Index: src/core/org/apache/jmeter/threads/AbstractThreadGroup.java
===================================================================
--- src/core/org/apache/jmeter/threads/AbstractThreadGroup.java	(revision 1776125)
+++ src/core/org/apache/jmeter/threads/AbstractThreadGroup.java	(working copy)
@@ -251,6 +251,8 @@
 
     public abstract void start(int groupCount, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine);
 
+    public abstract JMeterThread addNewThread(int delay, StandardJMeterEngine engine);
+
     public abstract boolean verifyThreadsStopped();
 
     public abstract void waitThreadsStopped();
Index: src/core/org/apache/jmeter/threads/JMeterThread.java
===================================================================
--- src/core/org/apache/jmeter/threads/JMeterThread.java	(revision 1776125)
+++ src/core/org/apache/jmeter/threads/JMeterThread.java	(working copy)
@@ -50,6 +50,7 @@
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.collections.HashTree;
 import org.apache.jorphan.collections.HashTreeTraverser;
+import org.apache.jorphan.collections.ListedHashTree;
 import org.apache.jorphan.collections.SearchByClass;
 import org.apache.jorphan.logging.LoggingManager;
 import org.apache.jorphan.util.JMeterError;
@@ -977,4 +978,12 @@
         this.threadGroup = group;
     }
 
+    public ListedHashTree getTestTree() {
+        return (ListedHashTree) testTree;
+    }
+
+    public ListenerNotifier getNotifier() {
+        return notifier;
+    }
+
 }
Index: src/core/org/apache/jmeter/threads/ThreadGroup.java
===================================================================
--- src/core/org/apache/jmeter/threads/ThreadGroup.java	(revision 1776125)
+++ src/core/org/apache/jmeter/threads/ThreadGroup.java	(working copy)
@@ -83,17 +83,24 @@
 
     // List of active threads
     private final Map<JMeterThread, Thread> allThreads = new ConcurrentHashMap<>();
+    private final Object addThreadLock = new Object();
 
     /**
      * Is test (still) running?
      */
     private volatile boolean running = false;
 
+    private int groupNumber;
+
     /**
      * Are we using delayed startup?
      */
     private boolean delayedStartup;
 
+    private ListenerNotifier notifier;
+
+    private ListedHashTree threadGroupTree;
+
     /**
      * No-arg constructor.
      */
@@ -257,38 +264,46 @@
     }
 
     @Override
-    public void start(int groupCount, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
+    public void start(int groupNum, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
         running = true;
+        groupNumber = groupNum;
+        this.notifier = notifier;
+        this.threadGroupTree = threadGroupTree;
         int numThreads = getNumThreads();
         int rampUpPeriodInSeconds = getRampUp();
         float perThreadDelayInMillis = (float) (rampUpPeriodInSeconds * 1000) / (float) getNumThreads();
 
         delayedStartup = isDelayedStartup(); // Fetch once; needs to stay constant
-        log.info("Starting thread group number " + groupCount
+        log.info("Starting thread group number " + groupNumber
                 + " threads " + numThreads
                 + " ramp-up " + rampUpPeriodInSeconds
                 + " perThread " + perThreadDelayInMillis
                 + " delayedStart=" + delayedStartup);
         if (delayedStartup) {
-            threadStarter = new Thread(new ThreadStarter(groupCount, notifier, threadGroupTree, engine), getName()+"-ThreadStarter");
+            threadStarter = new Thread(new ThreadStarter(notifier, threadGroupTree, engine), getName()+"-ThreadStarter");
             threadStarter.setDaemon(true);
             threadStarter.start();
             // N.B. we don't wait for the thread to complete, as that would prevent parallel TGs
         } else {
             long now = System.currentTimeMillis(); // needs to be same time for all threads in the group
             final JMeterContext context = JMeterContextService.getContext();
-            for (int i = 0; running && i < numThreads; i++) {
-                JMeterThread jmThread = makeThread(groupCount, notifier, threadGroupTree, engine, i, context);
-                scheduleThread(jmThread, now); // set start and end time
-                jmThread.setInitialDelay((int)(i * perThreadDelayInMillis));
-                Thread newThread = new Thread(jmThread, jmThread.getThreadName());
-                registerStartedThread(jmThread, newThread);
-                newThread.start();
+            for (int threadNum = 0; running && threadNum < numThreads; threadNum++) {
+                startNewThread(notifier, threadGroupTree, engine, threadNum, context, now, (int)(threadNum * perThreadDelayInMillis));
             }
         }
-        log.info("Started thread group number "+groupCount);
+        log.info("Started thread group number "+groupNumber);
     }
 
+    private JMeterThread startNewThread(ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine,
+            int threadNum, final JMeterContext context, long now, int delay) {
+        JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, threadNum, context);
+        scheduleThread(jmThread, now); // set start and end time
+        jmThread.setInitialDelay(delay);
+        Thread newThread = new Thread(jmThread, jmThread.getThreadName());
+        registerStartedThread(jmThread, newThread);
+        newThread.start();
+        return jmThread;
+    }
     /**
      * Register Thread when it starts
      * @param jMeterThread {@link JMeterThread}
@@ -298,7 +313,7 @@
         allThreads.put(jMeterThread, newThread);
     }
 
-    private JMeterThread makeThread(int groupCount,
+    private JMeterThread makeThread(
             ListenerNotifier notifier, ListedHashTree threadGroupTree,
             StandardJMeterEngine engine, int i, 
             JMeterContext context) { // N.B. Context needs to be fetched in the correct thread
@@ -311,7 +326,7 @@
         jmeterThread.setThreadNum(i);
         jmeterThread.setThreadGroup(this);
         jmeterThread.setInitialContext(context);
-        final String threadName = groupName + " " + (groupCount) + "-" + (i + 1);
+        final String threadName = groupName + " " + groupNumber + "-" + (i + 1);
         jmeterThread.setThreadName(threadName);
         jmeterThread.setEngine(engine);
         jmeterThread.setOnErrorStopTest(onErrorStopTest);
@@ -321,6 +336,21 @@
         return jmeterThread;
     }
 
+    @Override
+    public JMeterThread addNewThread(int delay, StandardJMeterEngine engine) {
+        long now = System.currentTimeMillis();
+        JMeterContext context = JMeterContextService.getContext();
+        JMeterThread newJmThread;
+        synchronized (addThreadLock) {
+            int numThreads = getNumThreads();
+            newJmThread = startNewThread(notifier, threadGroupTree, engine, numThreads, context, now, delay);
+            setNumThreads(numThreads + 1);
+        }
+        JMeterContextService.addTotalThreads( 1 );
+        log.info("Started new thread in group " + groupNumber );
+        return newJmThread;
+    }
+
     /**
      * Stop thread called threadName:
      * <ol>
@@ -504,15 +534,13 @@
      */
     class ThreadStarter implements Runnable {
 
-        private final int groupCount;
         private final ListenerNotifier notifier;
         private final ListedHashTree threadGroupTree;
         private final StandardJMeterEngine engine;
         private final JMeterContext context;
 
-        public ThreadStarter(int groupCount, ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
+        public ThreadStarter(ListenerNotifier notifier, ListedHashTree threadGroupTree, StandardJMeterEngine engine) {
             super();
-            this.groupCount = groupCount;
             this.notifier = notifier;
             this.threadGroupTree = threadGroupTree;
             this.engine = engine;
@@ -584,7 +612,7 @@
                     if (usingScheduler && System.currentTimeMillis() > endtime) {
                         break; // no point continuing beyond the end time
                     }
-                    JMeterThread jmThread = makeThread(groupCount, notifier, threadGroupTree, engine, i, context);
+                    JMeterThread jmThread = makeThread(notifier, threadGroupTree, engine, i, context);
                     jmThread.setInitialDelay(0);   // Already waited
                     if (usingScheduler) {
                         jmThread.setScheduled(true);
