Saya memiliki metode dengan a HandlerThread
. Nilai diubah di dalam Thread
dan saya ingin mengembalikannya ke test()
metode. Apakah ada cara untuk melakukan ini?
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
sumber
sumber
Jawaban:
Anda dapat menggunakan array variabel final lokal. Variabel harus berjenis non-primitif, sehingga Anda dapat menggunakan array. Anda juga perlu menyinkronkan kedua utas, misalnya menggunakan 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. }
Anda juga dapat menggunakan
Executor
danCallable
seperti ini: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(); }
sumber
Biasanya Anda akan melakukannya seperti ini
public class Foo implements Runnable { private volatile int value; @Override public void run() { value = 2; } public int getValue() { return value; } }
Kemudian Anda dapat membuat utas dan mengambil nilainya (mengingat nilainya telah ditetapkan)
Foo foo = new Foo(); Thread thread = new Thread(foo); thread.start(); thread.join(); int value = foo.getValue();
tl;dr
utas tidak dapat mengembalikan nilai (setidaknya tidak tanpa mekanisme panggilan balik). Anda harus mereferensikan utas seperti kelas biasa dan menanyakan nilainya.sumber
The method getValue() is undefined for the type Thread
.t.getValue()
menjadifoo.getValue()
.Thread t = new Thread(foo); t.start(); t.join(); foo.getValue();
. Thet.join()
blok sampai thread selesai.Apa yang Anda cari mungkin adalah
Callable<V>
antarmuka yang menggantikanRunnable
, dan mengambil nilai denganFuture<V>
objek, yang juga memungkinkan Anda menunggu hingga nilai telah dihitung. Anda dapat mencapai ini denganExecutorService
, yang dapat Anda peroleh dariExecutors.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(); }
sumber
Bagaimana dengan solusi ini?
Itu tidak menggunakan kelas Thread, tetapi itu IS bersamaan, dan dengan cara itu melakukan apa yang Anda minta
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;} });
Sekarang yang Anda lakukan hanyalah mengatakan
value.get()
kapan pun Anda perlu mengambil nilai yang dikembalikan, utas dimulai begitu Anda memberikanvalue
nilai sehingga Anda tidak perlu mengatakannyathreadName.start()
.Apa
Future
itu, adalah janji untuk program, Anda berjanji pada program bahwa Anda akan mendapatkan nilai yang dibutuhkannya dalam waktu dekatJika Anda memanggilnya
.get()
sebelum selesai, utas yang memanggilnya hanya akan menunggu sampai selesaisumber
Jika Anda menginginkan nilai dari metode pemanggilan, maka itu harus menunggu hingga utas selesai, yang membuat penggunaan utas sedikit tidak berguna.
Untuk menjawab pertanyaan Anda secara langsung, nilai dapat disimpan dalam objek yang bisa berubah apa pun, baik metode pemanggil maupun utas yang memiliki referensi. Anda bisa menggunakan bagian luarnya
this
, tetapi itu tidak akan berguna selain untuk contoh-contoh yang sepele.Sedikit catatan tentang kode dalam pertanyaan: Memperluas
Thread
biasanya gaya yang buruk. Memang memperpanjang kelas secara tidak perlu adalah ide yang buruk. Saya melihat Andarun
metode disinkronkan karena beberapa alasan. Sekarang sebagai objek dalam kasus ini adalahThread
Anda dapat mengganggu apa pun yangThread
menggunakan kunci untuk (dalam implementasi referensi, ada hubungannya denganjoin
, IIRC).sumber
Dari Java 8 dan seterusnya kami punya
CompletableFuture
. Dalam kasus Anda, Anda dapat menggunakan metode inisupplyAsync
untuk mendapatkan hasil setelah eksekusi.Temukan beberapa referensi di sini .
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> yourMethod()); completableFuture.get() //gives you the value
sumber
Menggunakan Future yang dijelaskan dalam jawaban di atas melakukan tugasnya, tetapi sedikit kurang signifikan karena f.get (), memblokir utas hingga mendapatkan hasil, yang melanggar konkurensi.
Solusi terbaik adalah menggunakan ListenableFuture Guava. Sebuah contoh :
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) { } };
sumber
Dengan sedikit modifikasi pada kode Anda, Anda dapat melakukannya dengan cara yang lebih umum.
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();
Solusi:
Handler
di UI Thread, yang disebut sebagairesponseHandler
Handler
dariLooper
UI Thread.HandlerThread
, posting pesan tentang iniresponseHandler
handleMessgae
menunjukkanToast
nilai yang diterima dari pesan. Objek Pesan ini bersifat umum dan Anda dapat mengirim jenis atribut yang berbeda.Dengan pendekatan ini, Anda dapat mengirim beberapa nilai ke thread UI pada titik waktu yang berbeda. Anda dapat menjalankan (memposting) banyak
Runnable
objek di siniHandlerThread
dan masing-masingRunnable
dapat mengatur nilai dalamMessage
objek, yang dapat diterima oleh UI Thread.sumber