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?
3 Réponses :
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
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();
}
}
}
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
@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é
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();
}
}
}
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
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
varde la même manière que vous passeznew Date ()au constructeur et appeleztestdepuisrun () < / code> méthode? Si la valeurvarn'est connue du thread principal qu'après le démarrage dethreadUpdater, 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
runpour la mauvaise chose. Vous devriez faire enrunce que vous faites actuellement dansgetPageJe 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