组合两个Runnable对象

时间:2011-01-11 19:58:39

标签: java multithreading runnable green-threads

比如说我有一个名为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();
    }

对不起,如果没有解释,请发表评论,如果您需要澄清。

谢谢!

5 个答案:

答案 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();
}