比如说我有一个名为RunnableA的Runnable可以执行某些操作。我还有一个名为RunnableB的Runnable,可以执行其他操作。有没有办法可以将这两个Runnables组合在一起,以便它们能够在同一个线程中运行?
问题的第二部分是,如果可以的话,我可以指定它们将运行的顺序吗?
编辑!:我之所以这样做是因为我需要在EDT上运行代码,但其他一些代码需要在另一个线程上运行。请看下面的代码。像这样的东西
public final class CompoundRunnable implements Runnable
{
private final Iterable runnables;
public CompoundRunnable(Iterable 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();
}
}
}
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();
}
对不起,如果没有解释,请发表评论,如果您需要澄清。
谢谢!
答案 0 :(得分:8)
嗯,你当然可以创建一个Runnable
,它只运行一个runnable而另一个运行:
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();
}
}
更一般地说,您可以使用Iterable<Runnable>
,复制所有Runnable
引用,然后按顺序运行它们。例如:
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();
}
}
}
答案 1 :(得分:3)
不确定。只需创建另一个runnable,它可以调用两个现有Runnable的run方法作为其实现的一部分。您可以使用Runnables等列表来创建包装Runnable专用或通用。
public Runnable combineRunnables(Runnable a, Runnable b)
{
Runnable retVal = new Runnable()
{
public void run()
{
a.run();
b.run();
}
};
return retVal;
}
或许令人困惑的是Runnable与线程的关联。 Runnable接口没有绑定到线程,并且它本身没有任何线程语义,因此您可以轻松地将它组合起来,而不会以某种方式遇到线程状态的麻烦。
答案 2 :(得分:2)
是的,你当然可以将它们结合起来。一般来说,除了调用其他对象之外,runnable内部应该没有太多内容,以实际完成工作。你能不能只拿走你需要的runnables的“内部”,并在你想要的上下文中执行它们。
如果你想确保事情一个接一个地执行,而不是同时你可以使用SingleThreadExecutorService并给它们Runnables。它将一次执行一个。
如果你真的想要运行多个runnable,那么就可以这样做(第一个RuntimeException将退出)。
请注意静态便捷方法,因此您可以说“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);
}
}
答案 3 :(得分:2)
另一种变化。
public static Runnable combineRunnables(final Runnable... runnables) {
return new Runnable() {
public void run() {
for(Runnable r: runnables) r.run();
}
};
}
答案 4 :(得分:1)
令我惊讶的是,没有人提出更灵活的方法,与现有答案相比,这恰好也是最简单,最短的解决方案。
只需创建一个新类RunList
,该类将其中一个具体的List
实现(例如ArrayList
)子类化,然后声明它实现Runnable
public class RunList extends ArrayList<Runnable> implements Runnable {
@Override
public void run() {
for (Runnable runner : this) {
runner.run();
}
}
}
定义了该类之后,您可以继续进行定义:
RunList runList = new RunList()
然后使用要运行的所有runList
填充Runnables
。现在,您可以使用完整的Java语言和标准库来对列表进行重新排序或常规操作。
下面包括一些示例(未经测试)用法。
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();
}