001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014: * License for the specific language governing permissions and limitations
015: * under the License.
016: *
017: */
018:
019: package org.apache.jmeter.timers;
020:
021: import java.io.Serializable;
022:
023: import org.apache.jmeter.testbeans.TestBean;
024: import org.apache.jmeter.testelement.AbstractTestElement;
025: import org.apache.jmeter.threads.JMeterContextService;
026: import org.apache.jorphan.logging.LoggingManager;
027: import org.apache.log.Logger;
028:
029: /**
030: * The purpose of the SyncTimer is to block threads until X number of threads
031: * have been blocked, and then they are all released at once. A SyncTimer can
032: * thus create large instant loads at various points of the test plan.
033: *
034: * @author mike
035: *
036: */
037: public class SyncTimer extends AbstractTestElement implements Timer,
038: Serializable, TestBean {
039: private static final long serialVersionUID = 2;
040:
041: private static final Logger log = LoggingManager
042: .getLoggerForClass();
043:
044: // Must be an Object so it will be shared between threads
045: private int[] timerCounter = new int[] { 0 };
046:
047: private transient Object sync = new Object();
048:
049: private int groupSize;
050:
051: // Ensure transient object is created by the server
052: private Object readResolve() {
053: sync = new Object();
054: return this ;
055: }
056:
057: /**
058: * @return Returns the numThreads.
059: */
060: public int getGroupSize() {
061: return groupSize;
062: }
063:
064: /**
065: * @param numThreads
066: * The numThreads to set.
067: */
068: public void setGroupSize(int numThreads) {
069: this .groupSize = numThreads;
070: }
071:
072: /*
073: * (non-Javadoc)
074: *
075: * @see org.apache.jmeter.timers.Timer#delay()
076: */
077: public long delay() {
078: synchronized (sync) {
079: timerCounter[0]++;
080: final int groupSz = getGroupSize();
081: final int count = timerCounter[0];
082: if ((groupSz == 0 && count >= JMeterContextService
083: .getNumberOfThreads())
084: || (groupSz > 0 && count >= groupSz)) {
085: sync.notifyAll();
086: } else {
087: try {
088: sync.wait();
089: } catch (InterruptedException e) {
090: log.warn(e.getLocalizedMessage());
091: }
092: }
093: timerCounter[0] = 0; // Reset for next time
094: }
095: return 0;
096: }
097:
098: /**
099: * We have to control the cloning process because we need some cross-thread
100: * communication if our synctimers are to be able to determine when to block
101: * and when to release.
102: */
103: public Object clone() {
104: SyncTimer newTimer = (SyncTimer) super.clone();
105: newTimer.timerCounter = timerCounter;
106: newTimer.sync = sync;
107: return newTimer;
108: }
109:
110: }
|