3
votes

Appeler et passer le paramètre à la méthode dans un autre thread

J'ai créé ce petit projet pour montrer ce que je veux faire, mais en réalité il sera utilisé dans une grande application qui utilise environ 60 threads différents.

J'ai deux classes

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();
        }
    }
}

et

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
    }
}

Depuis le thread principal, je veux pouvoir appeler la méthode getPage mais l'exécuter sur le httpThread1 que nous avons démarré et initialisé OkHttpClient client

Est-ce possible? comment faire?


11 commentaires

Quel est le problème avec updater.test (someVar) ?


updater.test ?


le test ne serait-il pas exécuté sur le thread principal? pas le nouveau fil que j'ai commencé pour le programme de mise à jour?


@Arya Votre dernière phrase dit Comment puis-je appeler test depuis le fil principal ...


@ernest_k oui, mais je veux que la méthode s'exécute sur la nouvelle méthode que nous avons démarrée pour le programme de mise à jour


@Arya C'est un peu flou. Pourquoi ne pas passer var de la même manière que vous passez new Date () au constructeur et appelez test depuis run () < / code> méthode? Si la valeur var n'est connue du thread principal qu'après le démarrage de threadUpdater , vous voudrez peut-être utiliser des choses comme les rappels ...


Je vais éditer ceci avec plus de clarté. j'y travaille


"la méthode à exécuter sur la nouvelle méthode" - C'est un peu flou comme l'a dit @ernest_k. Pourquoi avez-vous besoin de créer un autre fil de toute façon?


J'ai mis à jour la question. Devrait être clair maintenant


@Arya Je pense que vous utilisez la méthode run pour la mauvaise chose. Vous devriez faire en run ce que vous faites actuellement dans getPage


Je comprends que je peux le faire dans cet exemple. Mais j'en ai besoin pour un projet beaucoup plus gros et après l'initialisation, il y a des moments où un thread différent doit appeler et passer un paramètre à un autre thread


3 Réponses :


0
votes

Vous pouvez appeler la méthode test dans la classe Updater comme ceci: updater.test (yourVarHere)
Pour appeler une méthode dans un thread distinct, consultez cette question
Vous pouvez également consulter le tutoriel sur la concurrence Java


0 commentaires

1
votes

Runnable # run est la méthode conçue pour effectuer le travail réel d'un objet Runnable . Vous devrez donc lui faire faire ce que vous faites actuellement dans getPage .

Vous pouvez utiliser state pour stocker url et enregistrer la réponse dans un champ différent . Voir d'autres commentaires sur la façon dont vous pouvez refactoriser cela pour le simplifier encore plus. Mais à partir du code actuel, les changements les plus simples pourraient être:

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();
}

Et dans votre méthode main :

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();
        }
    }
}


6 commentaires

L'exemple du futur est très intéressant. Je vais voir si je peux l'utiliser dans le projet principal


Dans la classe Main, j'obtiens une ligne rouge sous .supplyAsync (() avec l'erreur "La méthode supplyAsync (Supplier ) dans le type CompletableFuture n'est pas applicable pour les arguments (() - > {}) "


La méthode getPage est-elle une méthode void dans votre version de Http ?


@Arya Si vous préférez, vous pouvez le garder vide (peut-être voulez-vous récupérer la réponse avec un getter). S'il est nul, vous devrez utiliser CompletableFuture future = CompletableFuture.runAsync (() -> http.get ...


@ernest_k Cet exemple fonctionnera-t-il si l'utilisateur souhaite fournir une nouvelle URL pour chaque thread? Dans votre code, une fois que vous avez défini l'URL, chaque fil appellera cette URL. Que faire si l'utilisateur souhaite fournir une URL personnalisée à chaque thread en utilisant le même objet Http?


@PrashantPandey C'est pourquoi j'ai suggéré la deuxième approche. Il ne tient pas d'état pour une demande particulière. Ainsi, l'objet Http peut être réutilisé autant de fois que souhaité (en supposant que OkHttpClient est thread-safe). Il est juste important de noter que runAsync et supplyAsync utilisent le pool de fork-join. Si plus de threads sont nécessaires, il faut utiliser un pool de threads personnalisé



0
votes

Sur la base de votre question, je pense que vous pourriez faire ceci:

public class Main {

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

Et dans la classe principale:

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();
        }
    }
 }


3 commentaires

J'aime ça mais malheureusement je ne peux pas l'utiliser car dans mon projet principal, je dois utiliser la méthode Runnable car la classe étend déjà une autre classe


stackoverflow.com/questions/21871073/java-thread-vs-runnable < / a> C'est presque le même docs.oracle.com /javase/7/docs/api/java/lang/Thread.html


Dans le projet principal, j'ai la classe publique OkHttp étend les implémentations de WebSocketListener Runnable Je dois faire étend WebSocketListener je ne sais pas comment je peux utiliser votre exemple