Запуск кода в основном потоке из вторичного потока?
Это общий вопрос 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
});
});
Спасибо заранее!
Ответы
Ответ 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().