Question

J'ai une petite application qui a un fil de rendu. Tout ce fil ne se dessiner mes objets à leur emplacement actuel.

J'ai un code comme:

public void render()
{
    // ... rendering various objects

    if (mouseBall != null) mouseBall.draw()

}

J'ai aussi un certain gestionnaire de la souris qui crée et met mouseball à une nouvelle balle lorsque l'utilisateur clique sur la souris. L'utilisateur peut alors faire glisser la souris autour de la balle et suivra où la souris va. Lorsque l'utilisateur relâche le ballon que j'ai un autre événement de la souris qui définit mouseball = null.

Le problème est, mon rendu boucle est en cours d'exécution assez vite que parfois aléatoire conditionnel (mouseball! = Null) retourne vrai, mais dans cette fraction de seconde après ce point l'utilisateur lâcherez de la souris et je vais obtenir une exception de nullpointer pour tenter .draw () sur un objet nul.

Quelle est la solution à un problème comme celui-ci?

Était-ce utile?

La solution

Le problème réside dans le fait que vous accédez à deux fois mouseBall, une fois pour vérifier si elle est pas et une autre pour null appeler une fonction sur elle. Vous pouvez éviter ce problème en utilisant un temporaire comme celui-ci:

public void render()
{
    // ... rendering various objects
    tmpBall = mouseBall;
    if (tmpBall != null) tmpBall.draw();
}

Autres conseils

Vous devez synchroniser les cas et d'en tirer des déclarations afin qu'ils soient garantis pour être exécuté comme une séquence atomique. En Java, cela serait fait comme ceci:

    
public void render()
{
    // ... rendering various objects
    synchronized(this) {
        if (mouseBall != null) mouseBall .draw();
   }
}

Je sais que vous avez déjà accepté d'autres réponses, mais une troisième option serait d'utiliser la classe AtomicReference du package java.util.concurrent.atomic. Cela permet la récupération, la mise à jour et comparer les opérations qui agissent atomiquement sans que vous ayez besoin de code de soutien. Donc, dans votre exemple:

public void render()
{
    AtomicReference<MouseBallClass> mouseBall = ...;

    // ... rendering various objects
    MouseBall tmpBall = mouseBall.get();
    if (tmpBall != null) tmpBall.draw();
}

Cela semble très similaire à la solution de Greg, et ils sont conceptuellement similaires en ce sens dans les coulisses de la volatilité de l'utilisation pour assurer la fraîcheur des valeurs, et de prendre une copie temporaire afin d'appliquer une condition avant d'utiliser la valeur.

Par conséquent, l'exemple exact utilisé ici est pas bon pour montrer la puissance des AtomicReferences. Pensez à la place que votre autre thread mettra à jour le mouseball vairable que si elle était déjà nul - un langage utile pour différents blocs de style d'initialisation du code. Dans ce cas, il serait généralement indispensable d'utiliser la synchronisation, pour faire en sorte que si vous avez coché et trouvé la balle était nulle, il toujours est nulle lorsque vous avez essayé de le mettre (sinon vous êtes de retour dans les domaines de votre problème d'origine). Cependant, avec l'AtomicReference vous pouvez dire simplement:

mouseBall.compareAndSet(null, possibleNewBall);

parce que c'est une opération atomique, donc si un thread « voit » la valeur comme nulle, il établira également la référence possibleNewBall avant que d'autres threads ont la chance de le lire.

Un autre idiome agréable avec des références atomiques est si vous définissez inconditionnellement quelque chose mais que vous devez effectuer une sorte de nettoyage avec la valeur ancienne. Dans ce cas, vous pouvez dire:

   MouseBall oldBall = mouseBall.getAndSet(newMouseBall);
   // Cleanup code using oldBall

AtomicInteger ont ces avantages et plus; la méthode getAndIncrement () est merveilleux pour les compteurs partagés dans le monde que vous pouvez garantir chaque appel à elle retourne une valeur distincte, quel que soit l'entrelacement de fils. Sécurité des threads avec un minimum d'agitation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top