Объединение двух объектов Runnable - PullRequest
2 голосов
/ 11 января 2011

Скажем, например, что у меня есть Runnable с именем RunnableA, который что-то делает.У меня также есть Runnable под названием RunnableB, который делает что-то еще.Можно ли как-нибудь объединить эти два Runnables, чтобы они работали в одном потоке?

Вторая часть вопроса: если это возможно, могу ли я указать порядок их запуска?in?

EDIT !: Причина, по которой я хотел это сделать, заключалась в том, что мне нужно запустить код в 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 ]

8 голосов
/ 11 января 2011

Ну, вы, безусловно, можете создать 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();
        }
    }
}
3 голосов
/ 11 января 2011

Конечно.Просто создайте другой runnable, который вызывает методы run двух ваших существующих Runnable как часть его реализации.Вы можете сделать обертку Runnable специально построенной или универсальной со списком Runnable и т. Д.

public Runnable combineRunnables(Runnable a, Runnable b)
{
   Runnable retVal = new Runnable()
   {
        public void run()
        {
            a.run();
            b.run();
        } 
   };

   return retVal;
}

Возможно, вас смущает ассоциация Runnable с потоками.Интерфейс Runnable не привязан к потокам и сам по себе не имеет никакой семантики потоков, поэтому вы можете легко объединить его, как описано выше, без каких-либо проблем с состояниями потоков.

2 голосов
/ 12 января 2011

Еще один вариант.

public static Runnable combineRunnables(final Runnable... runnables) {
   return new Runnable() {
        public void run() {
            for(Runnable r: runnables) r.run();
        } 
   };
}
2 голосов
/ 11 января 2011

Да, конечно, вы можете объединить их. В общем, внутри исполняемого файла не должно быть ничего, кроме вызова какого-либо другого объекта, чтобы фактически выполнить работу. Можете ли вы не просто взять «внутренности» необходимых вам исполняемых модулей и выполнить их в нужном вам контексте.

Если вы хотите, чтобы все выполнялось просто одно за другим, а не в одно и то же время, вы можете использовать SingleThreadExecutorService и предоставить им Runnables. Он будет выполняться по одному за раз.

Если вы действительно хотите запустить несколько runnables, вы можете сделать это следующим образом (первое RuntimeException завершится).

Обратите внимание на метод статического удобства, чтобы вы могли сказать «новый поток (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);
    }
}
...