3

例如,假设我有一个名为 RunnableA 的 Runnable,它可以做一些事情。我还有一个名为 RunnableB 的 Runnable,它可以做其他事情。有没有办法可以将这两个 Runnable 组合起来,以便它们在同一个线程中运行?

问题的第二部分是如果这是可能的,那么我可以指定它们运行的​​顺序吗?

编辑!:我想这样做的原因是因为我需要在 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();
    }

抱歉,如果没有很好地解释,如果您需要澄清,请发表评论。

谢谢!

4

5 回答 5

8

那么你当然可以创建一个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();
        }
    }
}
于 2011-01-11T20:01:58.777 回答
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 接口不依赖于线程,并且它本身没有任何线程语义,因此您可以像上面那样轻松地组合它,而不会以某种方式陷入线程状态的麻烦。

于 2011-01-11T20:01:39.077 回答
2

是的,您当然可以将它们结合起来。但总的来说,除了调用其他对象来实际完成工作之外,runnable 内部不应该有太多内容。您能否仅获取所需的可运行文件的“内部”并在所需的上下文中执行它们。

如果您想确保事情只是一个接一个地执行,而不是同时执行,您可以使用 SingleThreadExecutorService 并为它们提供 Runnables。它将一次执行一个。

如果您真的想运行多个可运行文件,那么您可以这样做(第一个 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);
    }
}
于 2011-01-11T20:12:31.767 回答
2

另一种变体。

public static Runnable combineRunnables(final Runnable... runnables) {
   return new Runnable() {
        public void run() {
            for(Runnable r: runnables) r.run();
        } 
   };
}
于 2011-01-11T21:51:45.977 回答
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();
}
于 2020-06-08T05:05:14.677 回答