/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

package org.apache.jmeter.threads;

/**
 * @version $Revision$
 */
public final class JMeterContextService {
	static private ThreadLocal threadContext = new ThreadLocal() {
		public Object initialValue() {
			return new JMeterContext();
		}
	};

	private static long testStart = 0;

	private static int numberOfThreads = 0; // Active thread count
    
    private static int totalThreads = 0;

	/**
	 * Private constructor to prevent instantiation.
	 */
	private JMeterContextService() {
	}

	static public JMeterContext getContext() {
		return (JMeterContext) threadContext.get();
	}

	static public void startTest() {//TODO should this be synchronized?
		if (testStart == 0) {
			numberOfThreads = 0;
			testStart = System.currentTimeMillis();
			threadContext = new ThreadLocal() {
				public Object initialValue() {
					return new JMeterContext();
				}
			};
		}
	}

	static synchronized void incrNumberOfThreads() {
		numberOfThreads++;
	}

	static synchronized void decrNumberOfThreads() {
		numberOfThreads--;
	}

	static public synchronized int getNumberOfThreads() {
		return numberOfThreads;
	}

	static public void endTest() {//TODO should this be synchronized?
		testStart = 0;
		numberOfThreads = 0;
	}

	static public long getTestStartTime() {// NOT USED
		return testStart;
	}

    public static synchronized int getTotalThreads() {
        return totalThreads;
    }

    public static synchronized void addTotalThreads(int thisGroup) {
        totalThreads += thisGroup;
    }

    public static synchronized void clearTotalThreads() {
        totalThreads = 0;
    }
}

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

package org.apache.jmeter.threads;

/**
 * Provides context service for JMeter threads.
 * Keeps track of active and total thread counts.
 */
public final class JMeterContextService {
	static private ThreadLocal threadContext = new ThreadLocal() {
		public Object initialValue() {
			return new JMeterContext();
		}
	};

	private static long testStart = 0;

	private static int numberOfActiveThreads = 0;
    
    private static int totalThreads = 0;

	/**
	 * Private constructor to prevent instantiation.
	 */
	private JMeterContextService() {
	}

	static public JMeterContext getContext() {
		return (JMeterContext) threadContext.get();
	}

	static public synchronized void startTest() {
		if (testStart == 0) {
			numberOfActiveThreads = 0;
			testStart = System.currentTimeMillis();
			threadContext = new ThreadLocal() {
				public Object initialValue() {
					return new JMeterContext();
				}
			};
		}
	}

	/**
	 * Increment number of active threads.
	 */
	static synchronized void incrNumberOfThreads() {
		numberOfActiveThreads++;
	}

	/**
	 * Decrement number of active threads.
	 */
	static synchronized void decrNumberOfThreads() {
		numberOfActiveThreads--;
	}

	/**
	 * Get the number of currently active threads
	 * @return active thread count
	 */
	static public synchronized int getNumberOfThreads() {
		return numberOfActiveThreads;
	}

	static public synchronized void endTest() {
		testStart = 0;
		numberOfActiveThreads = 0;
	}

	static public synchronized long getTestStartTime() {// NOT USED
		return testStart;
	}

	/**
	 * Get the total number of threads (>= active)
	 * @return total thread count
	 */
    public static synchronized int getTotalThreads() {
        return totalThreads;
    }

    /**
     * Update the total number of threads
     * @param thisGroup number of threads in this thread group
     */
    public static synchronized void addTotalThreads(int thisGroup) {
        totalThreads += thisGroup;
    }

    /**
     * Set total threads to zero
     */
    public static synchronized void clearTotalThreads() {
        totalThreads = 0;
    }
}

Update Javadoc Ensure all accesses to counts are synchronized