【问题标题】:Call and pass parameter to method in another thread在另一个线程中调用并将参数传递给方法
【发布时间】:2019-06-01 05:36:24
【问题描述】:

我创建了这个小项目来展示我想要做什么,但实际上它将用于使用大约 60 个不同线程的大型应用程序中。

我有两节课

public class Main {

    public static void main(String[] args) {
        Http http = new Http();
        Thread threadHttp = new Thread(http, "httpThread1");
        threadHttp.start();

        http.getPage("http://google.com"); // <-- This gets called on 
                                           // the main thread, 
                                           //I want it to get called from the
                                            // "httpThread1" thread
    }
}

public class Http implements Runnable {
    volatile OkHttpClient client;

    @Override
    public void run() {
        client = new OkHttpClient.Builder().readTimeout(10, TimeUnit.SECONDS).retryOnConnectionFailure(true).build();

    }

    public void getPage(String url) {
        Request request = new Request.Builder().url(url).build();

        try {
            Response response = client.newCall(request).execute();
            System.out.println(response.body().string());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

我希望能够从主线程调用getPage 方法,但让它在我们启动和初始化的httpThread1 上执行OkHttpClient client

这可能吗?怎么办?

【问题讨论】:

  • updater.test(someVar) 有什么问题?
  • updater.test?
  • 不会在主线程上测试运行吗?不是我为更新程序启动的新线程?
  • @Arya 你的最后一句话是How can I call test from the main thread ...
  • @Arya 有点不清楚。为什么不将var 传递给构造函数并从run() 方法中调用test 的方式与传递new Date() 的方式相同?如果var 值只有在threadUpdater 启动后才被主线程知道,那么您可能想要使用回调之类的东西...

标签: java multithreading


【解决方案1】:

Runnable#run 是设计用于完成Runnable 对象的实际工作的方法。所以你必须让它做你目前在getPage做的事情。

您可以使用状态来存储url,并将响应保存在不同的字段中。请参阅有关如何重构它以进一步简化它的更多 cmets。但从目前的代码来看,最简单的改动可能是:

class Http implements Runnable {

    //initialize Http. This can be done better perhaps
    volatile OkHttpClient client = new OkHttpClient.Builder()
            .readTimeout(10, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true).build();

    private Response response;

    private String url;

    public Http(String url) {
        this.url = url;
    }

    @Override
    public void run() {
        this.getPage(this.url);
    }

    public void getPage(String url) {
        Request request = new Request.Builder().url(url).build();

        try {
            this.response = client.newCall(request).execute();
            System.out.println(response.body().string());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在你的main 方法中:

Http http = new Http("http://google.com");
Thread threadHttp = new Thread(http, "httpThread1");
threadHttp.start();
threadHttp.join();
Response resp = http.getResponse();

但是,这可以通过使用期货大大简化。例如,它可能看起来很简单:

class Http {
    volatile OkHttpClient client = new OkHttpClient.Builder()
            .readTimeout(10, TimeUnit.SECONDS)
            .retryOnConnectionFailure(true).build();

    public Response getPage(String url) {
        Request request = new Request.Builder().url(url).build();

        try {
            this.response = client.newCall(request).execute();
            System.out.println(response.body().string());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

而且,使用期货,您的主要方法可以看起来更简单:

public static void main(String[] args) throws Exception {
    Http http = new Http();
    CompletableFuture<Response> future = 
            CompletableFuture.supplyAsync(() -> http.getPage("http://google.com"));

    //the preceding statement will call `getPage` on a different thread.
    //So you can do other things before blocking with next statement

    Response resp = future.join();
}

如果您需要更多地控制异步任务的运行方式,您甚至可以使用带有supplyAsync 的线程池。

【讨论】:

  • 期货的例子很有趣。我去看看能不能用在主项目里
  • 在主类中,.supplyAsync(() 下出现一条红线,错误为“CompletableFuture 类型中的方法 supplyAsync(Supplier) 不适用于参数 (() -> {})"
  • 在您的Http 版本中getPagevoid 方法吗?
  • @Arya 如果您愿意,可以将其保留为空(也许您想使用 getter 检索响应)。如果它是无效的,你必须使用CompletableFuture&lt;Void&gt; future = CompletableFuture.runAsync(() -&gt; http.get...
  • @ernest_k 如果用户想为每个线程提供一个新的 URL,这个例子会起作用吗?在您的代码中,一旦您设置了 URL,每个线程都会调用该 URL。如果用户想使用相同的 Http 对象为每个线程提供自定义 URL 怎么办?
【解决方案2】:

您可以像这样在Updater 类中调用test 方法:updater.test(yourVarHere)
要在单独的线程中调用方法,请参阅this question
您可能还想查看Java concurrency tutorial

【讨论】:

    【解决方案3】:

    根据您的问题,我认为您可能会这样做:

    class HttpThread extends Thread {
         volatile OkHttpClient client;
    
         HttpThread(Runnable target, String name) {
            super(target, name);
         }
    
         @Override
         public void run() {
            client = new OkHttpClient.Builder().readTimeout(10, TimeUnit.SECONDS).retryOnConnectionFailure(true).build();
         }
    
         public void getPage(String url) {
            Request request = new Request.Builder().url(url).build();
            try {
                Response response = client.newCall(request).execute();
                System.out.println(response.body().string());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
     }
    

    在主类中:

    public class Main {
    
       public static void main(String[] args) {
           Thread httpThread = new HttpThread(http, "httpThread1");
           httpThread.start();
           httpThread.getPage("http://google.com"); 
        }
    }
    

    【讨论】:

    猜你喜欢
    • 2018-05-19
    • 2016-12-21
    • 2018-08-08
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 2013-11-10
    相关资源
    最近更新 更多