📄 threadedbehaviourfactory.java
字号:
/*****************************************************************
JADE - Java Agent DEvelopment Framework is a framework to develop
multi-agent systems in compliance with the FIPA specifications.
Copyright (C) 2000 CSELT S.p.A.
GNU Lesser General Public License
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation,
version 2.1 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*****************************************************************/
package jade.core.behaviours;
//#MIDP_EXCLUDE_FILE
import jade.core.Agent;
import jade.core.NotFoundException;
import java.util.Vector;
import java.util.Enumeration;
/**
This class provides support for executing JADE Behaviours
in dedicated Java Threads. In order to do that it is sufficient
to add to an agent a normal JADE Behaviour "wrapped" into
a "threaded behaviour" as returned by the <code>wrap()</code> method
of this class (see the example below).
<pr><hr><blockquote><pre>
ThreadedBehaviourFactory tbf = new ThreadedBehaviourFactory();
Behaviour b = // create a JADE behaviour
addBehaviour(tbf.wrap(b));
</pre></blockquote><hr>
This class also provides methods to control the termination of
the threads dedicated to the execution of wrapped behaviours
<br>
<b>NOT available in MIDP</b>
<br>
@author Giovanni Caire - TILAB
*/
public class ThreadedBehaviourFactory {
// Thread states (only for debugging purpose)
private static final String CREATED_STATE = "CREATED";
private static final String RUNNING_STATE = "RUNNING";
private static final String CHECKING_STATE = "CHECKING";
private static final String BLOCKED_STATE = "BLOCKED";
private static final String SUSPENDED_STATE = "SUSPENDED";
private static final String TERMINATED_STATE = "TERMINATED";
private static final String INTERRUPTED_STATE = "INTERRUPTED";
private static final String ERROR_STATE = "ERROR";
private Vector threadedBehaviours = new Vector();
/**
* Wraps a normal JADE Behaviour <code>b</code> into a "threaded behaviour". Adding the
* wrapper behaviour to an agent results in executing <code>b</code> in a dedicated Java Therad.
*/
public Behaviour wrap(Behaviour b) {
return new ThreadedBehaviourWrapper(b);
}
/**
* @return The number of active threads dedicated to the execution of
* wrapped behaviours.
*/
public int size() {
return threadedBehaviours.size();
}
/**
* Interrupt all threaded behaviours managed by this ThreadedBehaviourFactory
*/
public void interrupt() {
ThreadedBehaviourWrapper[] tt = getWrappers();
for (int i = 0; i < tt.length; ++i) {
tt[i].interrupt();
}
}
/**
* Blocks until all threads dedicated to the execution of threaded
* behaviours complete.
* @param timeout The maximum timeout to wait for threaded behaviour
* termination.
* @return <code>true</code> if all threaded behaviour have actually
* completed, <code>false</code> otherwise.
*/
public synchronized boolean waitUntilEmpty(long timeout) {
long time = System.currentTimeMillis();
long deadline = time + timeout;
try {
while(!threadedBehaviours.isEmpty()) {
if (timeout > 0 && time >= deadline) {
// Timeout expired
break;
}
wait(deadline - time);
time = System.currentTimeMillis();
}
}
catch (InterruptedException ie) {
// Interrupted while waiting for threaded behaviour termination
}
return threadedBehaviours.isEmpty();
}
/**
* Interrupt a threaded behaviour. This method should be used to abort a threaded behaviour
* instead of getThread().interrupt() because i) the latter may have no effect if called just after
* the threaded behaviour suspended itself and ii) the threaded behaviour may be suspended
* and in this case its Thread is null.
* @return the Thread that was interrupted if any.
*/
public Thread interrupt(Behaviour b) throws NotFoundException {
ThreadedBehaviourWrapper wrapper = getWrapper(b);
if (wrapper != null) {
return wrapper.interrupt();
}
else {
throw new NotFoundException(b.getBehaviourName());
}
}
/**
* Suspend a threaded behaviour. This method has only effect if called by the threaded behaviour
* itself and has the effect of releasing its dedicated Java Thread. This can later be restored
* by means of the <code>resume()</code> method.
*/
public void suspend(Behaviour b) {
ThreadedBehaviourWrapper wrapper = getWrapper(b);
if (wrapper != null) {
wrapper.suspend();
}
}
/**
* Resume a threaded behaviour. Assign a new Java Thread to a threaded behaviour that is
* currently suspended.
*/
public void resume(Behaviour b) {
ThreadedBehaviourWrapper wrapper = getWrapper(b);
if (wrapper != null) {
wrapper.resume();
}
}
/**
@return the Thread dedicated to the execution of the Behaviour <code>b</code>
*/
public Thread getThread(Behaviour b) {
ThreadedBehaviourWrapper tb = getWrapper(b);
if (tb != null) {
return tb.getThread();
}
return null;
}
//#APIDOC_EXCLUDE_BEGIN
/**
* This method is declared public for debugging purpose only
* @return All the wrapper behaviours currently used by this ThreadedBehaviourFactory
*/
public ThreadedBehaviourWrapper[] getWrappers() {
synchronized (threadedBehaviours) {
ThreadedBehaviourWrapper[] wrappers = new ThreadedBehaviourWrapper[threadedBehaviours.size()];
for (int i = 0; i < wrappers.length; ++i) {
wrappers[i] = (ThreadedBehaviourWrapper) threadedBehaviours.elementAt(i);
}
return wrappers;
}
}
private ThreadedBehaviourWrapper getWrapper(Behaviour b) {
synchronized (threadedBehaviours) {
Enumeration e = threadedBehaviours.elements();
while (e.hasMoreElements()) {
ThreadedBehaviourWrapper tb = (ThreadedBehaviourWrapper) e.nextElement();
if (tb.getBehaviour().equals(b)) {
return tb;
}
}
return null;
}
}
/**
* Inner class ThreadedBehaviourWrapper
* This class is declared public for debugging purpose only
*/
public class ThreadedBehaviourWrapper extends Behaviour implements Runnable {
private Thread myThread;
private Behaviour myBehaviour;
private volatile boolean restarted = false;
private boolean finished = false;
private volatile boolean suspended = false;
private int exitValue;
// Only for debugging purpose
private volatile String threadState = CREATED_STATE;
private ThreadedBehaviourWrapper(Behaviour b) {
super(b.myAgent);
myBehaviour = b;
myBehaviour.setParent(new DummyParentBehaviour(myAgent, this));
}
public void onStart() {
// Be sure both the wrapped behaviour and its dummy parent are linked to the
// correct agent
myBehaviour.setAgent(myAgent);
myBehaviour.parent.setAgent(myAgent);
start();
}
private void start() {
// Start the dedicated thread
myThread = new Thread(this);
myThread.setName(myAgent.getLocalName()+"#"+myBehaviour.getBehaviourName());
myThread.start();
}
public void action() {
if (!finished) {
block();
}
}
public boolean done() {
return finished;
}
public int onEnd() {
// This check only makes sense if the ThreadedBehaviourWrapper is a child
// of a SerialBehaviour. In this case in fact the ThreadedBehaviourWrapper
// terminates, but the parent must remain blocked.
if (!myBehaviour.isRunnable()) {
block();
}
return exitValue;
}
/**
Propagate the parent to the wrapped behaviour.
NOTE that the <code>parent</code> member variable of the wrapped behaviour
must point to the DummyParentBehaviour --> From the wrapped behaviour
accessing the actual parent must always be retrieved through the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -