J'ai un thread code> code> qui expose une propriété que d'autres threads veulent accéder:
class MyThread extends Thread { private Foo foo; ... Foo getFoo() { return foo; } ... public void run() { ... foo = makeTheFoo(); ... } }
9 Réponses :
Vous pouvez utiliser les méthodes d'attente () et de notification (): p>
Exemple simple ici: P>
http://www.java-samples.com/showtutorial.php ? TutorialID = 306 p>
Certainement, je peux rouler une solution à la main. Je pense que c'est un peu plus complexe que celui-ci - le champ doit être volatile code> et nous avons besoin
notifier () code> pour commencer - alors j'espérais des commentaires sur quoi d'autre besoin ou une solution pré-emballée qui a définitivement raison.
@San dans ce cas, j'irais avec la suggestion de Djclayworth
Si je comprends bien, des choses concurrentes sont créées explicitement de ne pas attendre et faire ce que vous voulez tout de suite - mais si cela est possible du tout. Dans votre cas, vous devez attendre que quelque chose soit disponible, votre seule option est que votre seule option est, euh, to attendre () code>. En bref, il semble que votre façon de la décrire est la seule façon correcte. P>
En général notify () et notifytall () sont les méthodes souhaitées. Notifier () est dangereux si un seul élément crée le FOO et de nombreux threads pourraient l'attendre. Mais je pense qu'il y a d'autres problèmes ici. P>
Je ne ferais pas le fil le lieu de stocker le foo. Cela signifie que vous devez garder un filetage après la création de FOO. Pourquoi ne pas faire un autre objet pour stocker le FOO et avoir le fil de création d'écrire? P>
Alors j'aurais getfoo () testez FOO et qu'attendez seulement si c'était non NULL (n'oubliez pas de le synchroniser avec lui-même et avec le Setter FOO). P>
D'accord, je souhaite que ce n'était pas si. Dans ce cas, je dois vraiment faire l'objet dans la course (). C'est une application d'interface graphique avec des besoins étranges.
Si foo code> est initialisé une seule fois, un
CountownLatch code>
est un excellent ajustement. class MyThread extends Thread {
private final CountDownLatch latch = new CountDownLatch(1);
...
Foo getFoo() throws InterruptedException
{
latch.await(); /* Or use overload with timeout parameter. */
return foo;
}
@Override
public void run() {
foo = makeTheFoo()
latch.countDown();
}
}
Si l'initialisation est une offre unique, essayez Java.Util.ConCurrent.CountTownlatch . P>
est une initialisation paresseuse une option?
Pas dans ce cas que la FOO doit être faite dans l'autre thread.
Essayez le Nombre de comptownlatch Code>:
class MyThread extends Thread {
private volatile CountDownLatch latch;
private Foo foo;
MyThread(){
latch = new CountDownLatch(1);
}
...
Foo getFoo() {
latch.await(); // waits until foo is ready
return foo;
}
...
public void run() {
...
foo = makeTheFoo();
latch.countDown();// signals that foo is ready
...
}
}
En fait, il y a un bogue subtil ici: étant donné que loquet code> n'est pas
final code> ou
volatile code>, il n'est pas garanti d'être "visible" à d'autres threads. Pourrait ne pas être un problème dans la pratique, mais la garantie ne coûte rien vraiment.
J'utiliserais l'un des blockingQueue code>
dans java.util.concurrent code> plus précisément, s'il y a un fil en attente de foo et l'un produisant, je l'utilise
synchronousquee code> En cas de plus de producteurs et / ou plus de consommateurs, mon option par défaut est un
LinkedblockingQueue code>
, mais d'autres implémentations peuvent être mieux adaptées à votre application. Votre code devient alors: class MyThread extends Thread {
private SynchronousQueue<Foo> queue = new SynchronousQueue<Foo>();
...
Foo getFoo() {
Foo foo;
try {
foo = queue.take();
}
catch (InteruptedException ex) {
...stuff ...
}
return foo;
}
...
public void run() {
...
foo = makeTheFoo();
try {
queue.put(foo);
}
catch (InteruptedException ex) {
...stuff ...
}
...
}
}
Synchronousqueue est une construction pratique dans de nombreux cas, mais elle ne convient pas à l'exigence ici très bien: foo code> est uniquement initialisé une fois et lisait éventuellement plusieurs fois. Cela n'autoriserait que
foo code> à lire une fois. D'autres tentatives de lecture de la propriété bloqueraient pour toujours.
Oui, vous avez raison, j'avais manqué la partie "uniquement initialisée une fois". Je pensais que c'était plus une situation de producteur / consommateur.
Peut-être essayez peut-être ma classe FutureValue ...
import java.util.concurrent.CountDownLatch; public class FutureValue<T> { private CountDownLatch latch = new CountDownLatch(1); private T value; public void set(T value) throws InterruptedException, IllegalStateException { if (latch.getCount() == 0) { throw new IllegalStateException("Value has been already set."); } latch.countDown(); this.value = value; } /** * Returns the value stored in this container. Waits if value is not available. * * @return * @throws InterruptedException */ public T get() throws InterruptedException { latch.await(); return value; } } // Usage example class MyExampleClass { @SuppressWarnings("unused") private static void usageExample() throws InterruptedException { FutureValue<String> futureValue = new FutureValue<>(); // the thread that will produce the value somewhere new Thread(new Runnable() { @Override public void run() { try { futureValue.set("this is future"); } catch (InterruptedException e) { e.printStackTrace(); } } }).run(); String valueProducedSomewhereElse = futureValue.get(); } }