Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/226.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从线程返回值_Java_Android_Multithreading - Fatal编程技术网

Java 从线程返回值

Java 从线程返回值,java,android,multithreading,Java,Android,Multithreading,我有一个带有HandlerThread的方法。在线程中更改了一个值,我想将其返回到test()方法。有办法做到这一点吗 public void test() { Thread uiThread = new HandlerThread("UIHandler"){ public synchronized void run(){ int value; value = 2; //To be returned to test(

我有一个带有
HandlerThread
的方法。在
线程中更改了一个值,我想将其返回到
test()
方法。有办法做到这一点吗

public void test()
{   
    Thread uiThread = new HandlerThread("UIHandler"){
        public synchronized void run(){
            int value; 
            value = 2; //To be returned to test()
        }
    };
    uiThread.start();
}

通常你会这样做

 public class Foo implements Runnable {
     private volatile int value;

     @Override
     public void run() {
        value = 2;
     }

     public int getValue() {
         return value;
     }
 }
然后,您可以创建线程并检索该值(假定该值已设置)



tl;dr
线程无法返回值(至少在没有回调机制的情况下是如此)。您应该像普通类一样引用线程并请求值

您要查找的可能是
可调用的
接口,它代替了
可运行的
,并使用
未来的
对象检索值,该对象还允许您等待值计算完成。您可以通过执行器服务实现这一点,该服务可以从执行器.newSingleThreadExecutor()
获得

公共无效测试(){
int x;
ExecutorService es=Executors.newSingleThreadExecutor();
未来结果=es.submit(新的可调用(){
公共整数调用()引发异常{
//另一根线
返回2;
}
});
试一试{
x=result.get();
}捕获(例外e){
//失败
}
es.shutdown();
}

您可以使用局部最终变量数组。变量必须是非基元类型,因此可以使用数组。您还需要同步这两个线程,例如使用:

您还可以使用和,如下所示:

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 void test()抛出InterruptedException、ExecutionException
{   
ExecutorService executor=Executors.newSingleThreadExecutor();
Callable Callable=new Callable(){
@凌驾
公共整数调用(){
返回2;
}
};
未来=执行人提交(可调用);
//future.get()返回2,或者在线程死亡时引发异常,因此更安全
executor.shutdown();
}

如果希望从调用方法获得值,那么它应该等待线程完成,这使得使用线程有点毫无意义

为了直接回答您的问题,该值可以存储在调用方法和线程都有引用的任何可变对象中。您可以使用外部的
this
,但是除了一些简单的例子之外,它不会特别有用


关于问题中代码的一点注意事项:扩展
线程
通常是糟糕的风格。事实上,不必要地扩展类是一个坏主意。我注意到由于某种原因,您的
run
方法是同步的。现在,由于本例中的对象是
线程
,您可能会干扰
线程
使用其锁的任何内容(在参考实现中,与
连接
,IIRC有关)。

此解决方案如何

它不使用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;}
});
ExecutorService池=Executors.newFixedThreadPool(2);//创建一个线程池,供将来使用
Future value=pool.submit(new Callable()){
@凌驾
公共整数调用(){return 2;}
});
现在,只要说
value.get()
,每当需要获取返回的值时,线程就会在你给
value
一个值的那一刻启动,这样你就不必说
threadName.start()

未来是什么
是对程序的承诺,你向程序承诺你会在不久的将来得到它所需要的价值


如果在完成之前对其调用
.get()
,调用它的线程只需等待,直到它完成为止

使用上述答案中描述的Future来执行该任务,但与f.get()相比,它会阻塞线程直到得到结果,这违反了并发性

最好的解决办法是使用番石榴的上市产品。例如:

    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)
        {

        }
    };
ListenableFuture=MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1,newnamedthreadfactory)。submit(new Callable())
{
@凌驾
public Void call()引发异常
{
someBackgroundTask();
}
});
Futures.addCallback(future,newfuturecallback()
{
@凌驾
成功时公开作废(长期结果)
{
doSomething();
}
@凌驾
失效时的公共无效(可丢弃的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();
解决方案:

  • 在UI线程中创建一个
    处理程序
    ,称为
    responseHandler
  • 从UI线程的
    活套
    初始化此
    处理程序
  • HandlerThread
    中,在此
    responseHandler上发布消息
  • handleMessgae
    显示一个带有从消息接收的值的
    Toast
    。此消息对象是通用的,您可以发送不同类型的属性

  • 使用这种方法,您可以在不同的时间点向UI线程发送多个值这个
    HandlerThread
    上有许多
    Runnable
    对象,每个
    Runnable
    都可以在
    Message
    对象中设置值,UI线程可以接收这些值。

    从Java 8开始,我们就有了
    CompletableFuture
    。 在您的情况下,您可以使用方法
    supplyAsync
    在执行后获得结果

    请找一些参考资料

    CompletableFuture CompletableFuture
    =CompletableFuture.SupplySync(()->yourMethod());
    completableFuture.get()//为您提供值
    
    这里有一个更简洁的方法,您只需要对现有代码进行一些更改。目标是从线程中获取结果。它实际上不必是
    返回结果。相反,使用回调样式获取该结果并执行进一步的处理
    
    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;}
    });
    
        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();
    
        CompletableFuture<Integer> completableFuture
          = CompletableFuture.supplyAsync(() -> yourMethod());
    
       completableFuture.get() //gives you the value
    
    public class Test {
    
      public static void main(String[] args) {
        String str = args[0];
        int count = 0;
    
        Thread t = new Thread(() ->
          someFuncToRun(str, count, (value) -> {
            System.out.println(value);
            return value;
          }));
    
        t.start();
      }
      // Here I even run a recursive method because run things in the 
      // a thread sometime is to delegate those heavy lifting elsewhere
      public static String someFuncToRun(String str, int ctn, Callback<String> p) {
        ++ctn;
        if (ctn == 10) {
          System.out.println("End here");
          return p.cb(str);
        }
        System.out.println(ctn + " times");
        return someFuncToRun(str + " +1", ctn, p);
      }
    }
    
    // The key is here, this allow you to pass a lambda callback to your method 
    // update: use generic to allow passing different type of data
    // you could event make it <T,S> so input one type return another type  
    interface Callback<T> {
        public T cb(T a);
    }
    
    
    public static void main(String[] args) throws InterruptedException {
        AtomicInteger value = new AtomicInteger(0);
        Thread thread = new Thread(() -> value.set(2));
        thread.start();
        thread.join();
        System.out.println(value.get());
    }