스레드에서 값 반환
나는 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();
}
지역 최종 변수 배열을 사용할 수 있습니다. 변수는 기본이 아닌 유형이어야하므로 배열을 사용할 수 있습니다. 예를 들어 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
스레드는 값을 반환 할 수 없습니다 (적어도 콜백 메커니즘 없이는 안 됨). 일반 클래스와 같은 스레드를 참조하고 값을 요청해야합니다.
What you are looking for is probably the Callable<V>
interface in place of Runnable
, and retrieving the value with a Future<V>
object, which also lets you wait until the value has been computed. You can achieve this with an ExecutorService
, which you can get from 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();
}
How about this solution?
It doesn't use the Thread class, but it IS concurrent, and in a way it does exactly what you request
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;}
});
Now all you do is say value.get()
whenever you need to grab your returned value, the thread is started the very second you give value
a value so you don't ever have to say threadName.start()
on it.
What a Future
is, is a promise to the program, you promise the program that you'll get it the value it needs sometime in the near future
If you call .get()
on it before it's done, the thread that's calling it will simply just wait until it's done
If you want the value from the calling method, then it should wait for the thread to finish, which makes using threads a bit pointless.
To directly answer you question, the value can be stored in any mutable object both the calling method and the thread both have a reference to. You could use the outer this
, but that isn't going to be particularly useful other than for trivial examples.
A little note on the code in the question: Extending Thread
is usually poor style. Indeed extending classes unnecessarily is a bad idea. I notice you run
method is synchronised for some reason. Now as the object in this case is the Thread
you may interfere with whatever Thread
uses its lock for (in the reference implementation, something to do with join
, IIRC).
Using Future described in above answers does the job, but a bit less significantly as f.get(), blocks the thread until it gets the result, which violates concurrency.
Best solution is to use Guava's ListenableFuture. An example :
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)
{
}
};
Java 8 provides CompletableFuture . it will be the one stop solution for this. http://www.baeldung.com/java-completablefuture
With small modifications to your code, you can achieve it in a more generic way.
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();
Solution :
- Create a
Handler
in UI Thread,which is called asresponseHandler
- Initialize this
Handler
fromLooper
of UI Thread. - In
HandlerThread
, post message on thisresponseHandler
handleMessgae
shows aToast
with value received from message. This Message object is generic and you can send different type of attributes.
With this approach, you can send multiple values to UI thread at different point of times. You can run (post) many Runnable
objects on this HandlerThread
and each Runnable
can set value in Message
object, which can be received by UI Thread.
참고URL : https://stackoverflow.com/questions/9148899/returning-value-from-thread
'Programing' 카테고리의 다른 글
stdClass 객체를 다른 클래스로 변환 / 캐스트 (0) | 2020.09.18 |
---|---|
네이티브 개체와 호스트 개체의 차이점은 무엇입니까? (0) | 2020.09.18 |
반환 된 값이 null 인 경우 postgresql은 0을 반환합니다. (0) | 2020.09.18 |
Emacs를 다시 시작하지 않고 구성 다시로드 (0) | 2020.09.18 |
System.ComponentModel 기본값 속성 내에서 DateTime 속성의 기본값을 DateTime.Now로 설정 (0) | 2020.09.18 |