У меня есть метод с HandlerThread
. Значение изменяется внутри, Thread
и я хочу вернуть его test()
методу. Есть ли способ сделать это?
public void test()
{
Thread uiThread = new HandlerThread("UIHandler"){
public synchronized void run(){
int value;
value = 2; //To be returned to test()
}
};
uiThread.start();
}
java
android
multithreading
Neeta
источник
источник
Ответы:
Вы можете использовать локальный конечный массив переменных. Переменная должна быть непримитивного типа, поэтому вы можете использовать массив. Вам также необходимо синхронизировать два потока, например, с помощью CountDownLatch :
public void test() { final CountDownLatch latch = new CountDownLatch(1); final int[] value = new int[1]; Thread uiThread = new HandlerThread("UIHandler"){ @Override public void run(){ value[0] = 2; latch.countDown(); // Release await() in the test thread. } }; uiThread.start(); latch.await(); // Wait for countDown() in the UI thread. Or could uiThread.join(); // value[0] holds 2 at this point. }
Вы также можете использовать
Executor
иCallable
подобное:public void test() throws InterruptedException, ExecutionException { ExecutorService executor = Executors.newSingleThreadExecutor(); Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() { return 2; } }; Future<Integer> future = executor.submit(callable); // future.get() returns 2 or raises an exception if the thread dies, so safer executor.shutdown(); }
источник
Обычно вы делаете что-то вроде этого
public class Foo implements Runnable { private volatile int value; @Override public void run() { value = 2; } public int getValue() { return value; } }
Затем вы можете создать поток и получить значение (при условии, что значение было установлено)
Foo foo = new Foo(); Thread thread = new Thread(foo); thread.start(); thread.join(); int value = foo.getValue();
tl;dr
поток не может вернуть значение (по крайней мере, без механизма обратного вызова). Вы должны ссылаться на поток, как на обычный класс, и запрашивать значение.источник
The method getValue() is undefined for the type Thread
.t.getValue()
наfoo.getValue()
.Thread t = new Thread(foo); t.start(); t.join(); foo.getValue();
. Этиt.join()
блоки до резьбы закончена.То, что вы ищете, вероятно, - это
Callable<V>
интерфейс вместоRunnable
и получение значения с помощьюFuture<V>
объекта, что также позволяет вам подождать, пока значение не будет вычислено. Этого можно добиться с помощью объектаExecutorService
, из которого можно получитьExecutors.newSingleThreadExecutor()
.public void test() { int x; ExecutorService es = Executors.newSingleThreadExecutor(); Future<Integer> result = es.submit(new Callable<Integer>() { public Integer call() throws Exception { // the other thread return 2; } }); try { x = result.get(); } catch (Exception e) { // failed } es.shutdown(); }
источник
Как насчет этого решения?
Он не использует класс Thread, но он является параллельным и в некотором смысле делает именно то, что вы запрашиваете.
ExecutorService pool = Executors.newFixedThreadPool(2); // creates a pool of threads for the Future to draw from Future<Integer> value = pool.submit(new Callable<Integer>() { @Override public Integer call() {return 2;} });
Теперь все, что вы делаете, это говорите
value.get()
всякий раз, когда вам нужно получить возвращаемое значение, поток запускается в ту самую секунду, когда вы задаетеvalue
значение, поэтому вам никогда не придется об этом говоритьthreadName.start()
.Что
Future
есть, это обещание программе, вы обещаете программе, что вы получите то значение, которое ей нужно, когда-нибудь в ближайшем будущем.Если вы вызовете
.get()
его до того, как это будет сделано, вызывающий его поток просто подождет, пока он не будет выполнен.источник
Если вы хотите получить значение из вызывающего метода, то он должен дождаться завершения потока, что делает использование потоков немного бессмысленным.
Чтобы напрямую ответить на ваш вопрос, значение может быть сохранено в любом изменяемом объекте, и вызывающий метод, и поток имеют ссылку на. Вы можете использовать внешний
this
, но это не будет особенно полезно, кроме тривиальных примеров.Небольшое замечание по коду в вопросе: расширение
Thread
обычно плохой стиль. Действительно, без необходимости расширять классы - плохая идея. Я заметил, что вашrun
метод по какой-то причине синхронизирован. Теперь, поскольку объект в этом случае является объектом,Thread
вы можете вмешиваться во все, чтоThread
использует его блокировку (в эталонной реализации, что-то связанное сjoin
IIRC).источник
Начиная с Java 8 и далее у нас есть
CompletableFuture
. В вашем случае вы можете использовать методsupplyAsync
для получения результата после выполнения.Пожалуйста, найдите здесь ссылку .
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> yourMethod()); completableFuture.get() //gives you the value
источник
Использование Future, описанное в ответах выше, выполняет свою работу, но немного менее существенно, чем f.get (), блокирует поток до тех пор, пока он не получит результат, что нарушает параллелизм.
Лучшее решение - использовать ListenableFuture от Guava. Пример :
ListenableFuture<Void> future = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1, new NamedThreadFactory).submit(new Callable<Void>() { @Override public Void call() throws Exception { someBackgroundTask(); } }); Futures.addCallback(future, new FutureCallback<Long>() { @Override public void onSuccess(Long result) { doSomething(); } @Override public void onFailure(Throwable t) { } };
источник
С небольшими изменениями в вашем коде вы можете добиться этого более общим способом.
final Handler responseHandler = new Handler(Looper.getMainLooper()){ @Override public void handleMessage(Message msg) { //txtView.setText((String) msg.obj); Toast.makeText(MainActivity.this, "Result from UIHandlerThread:"+(int)msg.obj, Toast.LENGTH_LONG) .show(); } }; HandlerThread handlerThread = new HandlerThread("UIHandlerThread"){ public void run(){ Integer a = 2; Message msg = new Message(); msg.obj = a; responseHandler.sendMessage(msg); System.out.println(a); } }; handlerThread.start();
Решение :
Handler
поток пользовательского интерфейса, который называетсяresponseHandler
Handler
изLooper
потока пользовательского интерфейса.HandlerThread
, опубликуйте сообщение об этомresponseHandler
handleMessgae
показываетToast
значение, полученное из сообщения. Этот объект сообщения является универсальным, и вы можете отправлять различные типы атрибутов.При таком подходе вы можете отправлять несколько значений потоку пользовательского интерфейса в разное время. Вы можете запускать (публиковать) много
Runnable
объектов на этом,HandlerThread
и каждыйRunnable
может устанавливать значение вMessage
объекте, которое может быть получено потоком пользовательского интерфейса.источник