Подтвердить что ты не робот

Запуск кода в основном потоке из вторичного потока?

Это общий вопрос Java, а не первый Android!

Я хотел бы знать, как запускать код в основном потоке, из контекста вторичного потока. Например:

new Thread(new Runnable() {
        public void run() {
            //work out pi to 1,000 DP (takes a while!)

            //print the result on the main thread
        }
    }).start();

Что-то вроде этого - я понимаю, что мой пример немного беден, поскольку в Java вам не обязательно быть в основном потоке, чтобы что-то печатать, и что Swing также имеет очередь событий, но общая ситуация, когда вы возможно, потребуется запустить say Runnable в основном потоке, в то время как в контексте фонового потока.

EDIT: для сравнения - вот как бы я сделал это в Objective-C:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0UL), ^{
    //do background thread stuff

    dispatch_async(dispatch_get_main_queue(), ^{
        //update UI
    });
});

Спасибо заранее!

4b9b3361

Ответ 1

Нет универсального способа просто отправить какой-то код другому запущенному потоку и сказать: "Эй, ты, сделай это". Вам нужно будет поместить основной поток в состояние, в котором у него есть механизм для приема работы и ждет выполнения работы.

Вот простой пример настройки основного потока, чтобы ждать, чтобы получить работу из других потоков и запустить его по мере его поступления. Очевидно, вы хотели бы добавить способ фактически завершить программу и т.д....!

public static final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();

public static void main(String[] args) throws Exception {
    new Thread(new Runnable(){
        @Override
        public void run() {
            final int result;
            result = 2+3;
            queue.add(new Runnable(){
                @Override
                public void run() {
                    System.out.println(result);
                }
            });
        }
    }).start();

    while(true) {
        queue.take().run();
    }
}

Ответ 2

В случае, если вы находитесь на Android, использование обработчика должно выполнять эту работу?

new Handler(Looper.getMainLooper()).post(new Runnable () {
    @Override
    public void run () {
        ...
    }
});

Ответ 3

Старое обсуждение, но если речь идет о отправке запроса в основной поток (не в противоположном направлении), вы также можете сделать это с помощью фьючерсов. Основная цель - выполнить что-то в фоновом режиме и, когда оно будет закончено, получить результат:

public static void main(String[] args) throws InterruptedException, ExecutionException {
    // create the task to execute
    System.out.println("Main: Run thread");
    FutureTask<Integer> task = new FutureTask<Integer>(
            new Callable<Integer>() {

                @Override
                public Integer call() throws Exception {
                    // indicate the beginning of the thread
                    System.out.println("Thread: Start");

                    // decide a timeout between 1 and 5s
                    int timeout = 1000 + new Random().nextInt(4000);

                    // wait the timeout
                    Thread.sleep(timeout);

                    // indicate the end of the thread
                    System.out.println("Thread: Stop after " + timeout + "ms");

                    // return the result of the background execution
                    return timeout;
                }
            });
    new Thread(task).start();
    // here the thread is running in background

    // during this time we do something else
    System.out.println("Main: Start to work on other things...");
    Thread.sleep(2000);
    System.out.println("Main: I have done plenty of stuff, but now I need the result of my function!");

    // wait for the thread to finish if necessary and retrieve the result.
    Integer result = task.get();

    // now we can go ahead and use the result
    System.out.println("Main: Thread has returned " + result);
    // you can also check task.isDone() before to call task.get() to know
    // if it is finished and do somethings else if it is not the case.
}

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

Ответ 4

Возможно, вы захотите использовать "даже диспетчерский поток", где происходит большинство событий. Если вы используете свинг, то:

    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            Your code here.
        }
    });

Или создайте класс, который реализует Runnable и передает его в invokeLater().