Programing

스레드에서 값 반환

lottogame 2020. 9. 18. 19:12
반응형

스레드에서 값 반환


나는 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 :

  1. Create a Handler in UI Thread,which is called as responseHandler
  2. Initialize this Handler from Looper of UI Thread.
  3. In HandlerThread, post message on this responseHandler
  4. handleMessgae shows a Toast 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

반응형