Combining two Runnable objects
Say for example that I have a Runnable called RunnableA that does something. I also have a Runnable called RunnableB that does something else. Is there a way that I can combine these two Runnables someway so that they will run in the same thread?
The second part of the question is if this is possible, can I then specify the order that they will run in?
EDIT!: The reason why I wanted to do this was because I need to run code on the EDT but some of the other code needs to be run on another thread. Please take a look at the code below.
Something like this
public final class CompoundRunnable implements Runnable
{
private final Iterable runnables;
public CompoundRunnable(Iterable runnables)
{
// From Guava开发者_如何学JAVA. Easy enough to do by hand if necessary
this.runnables = Lists.newArrayList(runnables);
}
public CompoundRunnable(Runnable... runnables)
{
this(Arrays.asList(runnables));
}
@Override
public void run()
{
for (Runnable runnable : runnables)
{
runnable.run();
}
}
}
public void setStatusAndProgress(final String status,Runnable runnable)
{
Runnable startUpRunner = new Runnable()
{
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
setStatus(status);
selfReference.getProgressBar().setIndeterminate(true);
}
});
}
};
Runnable cleanUpRunner = new Runnable()
{
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
setStatus("");
getProgressBar().setIndeterminate(false);
}
});
}
};
Runnable theRunner = new CompoundRunnable(startUpRunner,runnable,cleanUpRunner);
new Thread(theRunner).start();
}
Sorry if this isnt explained well, post comments if you need clarification.
Thanks!
Well you can certainly create a Runnable
which just runs one runnable then the other:
public final class CompoundRunnable implements Runnable
{
private final Runnable first;
private final Runnable second;
public CompoundRunnable(Runnable first, Runnable second)
{
this.first = first;
this.second = second;
}
@Override
public void run()
{
first.run();
second.run();
}
}
More generally, you could make it take an Iterable<Runnable>
, copy all the Runnable
references, and then run them in order. For example:
public final class CompoundRunnable implements Runnable
{
private final Iterable<Runnable> runnables;
public CompoundRunnable(Iterable<Runnable> runnables)
{
// From Guava. Easy enough to do by hand if necessary
this.runnables = Lists.newArrayList(runnables);
}
public CompoundRunnable(Runnable... runnables)
{
this(Arrays.asList(runnables));
}
@Override
public void run()
{
for (Runnable runnable : runnables)
{
runnable.run();
}
}
}
Sure. Just create another runnable that calls the run methods of your two existing Runnable's as part of its implementation. You can make the wrapping Runnable purpose-built or generic with a list of Runnables, etc.
public Runnable combineRunnables(Runnable a, Runnable b)
{
Runnable retVal = new Runnable()
{
public void run()
{
a.run();
b.run();
}
};
return retVal;
}
Perhaps what's confusing you is association of Runnable with threads. The Runnable interface isn't tied to threads and doesn't by itself have any threading semantics, so you can easily combine it like above without somehow getting into trouble with thread states.
Yes you can of course combine them. In general though, there shouldn't be much inside a runnable except a call to some other object, to actually get the work done. Can you not just take the "insides" of the runnables you need and execute them in the context you want.
If you want to make sure things are simply executed one after the other, rather than at the same time you can use a SingleThreadExecutorService and give them the Runnables. It will execute one at a time.
If you really want to run multiple runnables then you can do it like this (the first RuntimeException will exit).
Note the static convenience method so you can say "new Thread(CompositeRunnable.combine(a,b,c,d....))"
public class CompositeRunnable implements Runnable {
private final Runnable[] runnables;
public CompositeRunnable(Runnable... runnables) {
this.runnables = runnables;
}
public void run() {
for (Runnable runnable : runnables) {
runnable.run();
}
}
public static Runnable combine(Runnable... runnables) {
return new CompositeRunnable(runnables);
}
}
Another variation.
public static Runnable combineRunnables(final Runnable... runnables) {
return new Runnable() {
public void run() {
for(Runnable r: runnables) r.run();
}
};
}
I'm surprised nobody suggested the more flexible approach, which just so happens to be also the simplest and and shortest solution compared to the existing answers.
Just create a new class RunList
that subclasses one of the concrete List
implementations (e.g. ArrayList
) and then declare it implements Runnable
public class RunList extends ArrayList<Runnable> implements Runnable {
@Override
public void run() {
for (Runnable runner : this) {
runner.run();
}
}
}
With that class defined, you can then go about defining:
RunList runList = new RunList()
And then populate runList
with all of the Runnables
you want to run. You now have the full Java language and standard library at your disposal here for reordering or general manipulation of the list.
Some example (untested) usage is included below.
public void testRunList() {
RunList list = new RunList();
// the venerable, straight-forward technique
for (int i = 0; i < 10; ++i) {
list.add(() -> {
/* i'th runnable */
});
}
// a bit of type juggling to concisely add an arbitrary number of Runnables to the list
list.addAll(Arrays.asList(
() -> { /* runnable 1 */ },
() -> { /* runnable 2 */ }
));
// or if you're just feeling frisky, these methods too are at your disposal!
Collections.shuffle(list);
list.run();
}
精彩评论