33 votes

Threading en Java : Comment verrouiller un objet ?

La fonction suivante s'exécute dans son propre thread :

private void doSendData()
{
    try {

           //writeToFile(); // just a temporary location of a call
           InetAddress serverAddr = InetAddress.getByName(serverAddress);
           serverAddr.wait(60000);
           //Log.d("TCP", "C: Connecting...");
           Socket socket = new Socket(serverAddr, portNumber);
           socket.setSoTimeout(3000);

               try {
                //Log.d("TCP", "C: Sending: '" + message + "'");
                PrintWriter out = new PrintWriter( new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())),true);
                String message = packData();
                out.println(message);
                Log.d("TCP", "C: Sent.");
                Log.d("TCP", "C: Done.");
                connectionAvailable = true;

             } catch(Exception e) {
                 Log.e("TCP", "S: Error", e);
                 connectionAvailable = false;

               } finally {
                  socket.close();
                  announceNetworkAvailability(connectionAvailable);
                }

         } catch (Exception e) {
              Log.e("TCP", "C: Error", e);
              announceNetworkAvailability(connectionAvailable);
         }
}

Lorsque l'exécution atteint la ligne serverAddr.wait(60000) il déclenche une exception :

java.lang.IllegalMonitorStateException: object not locked by thread before wait()

Quelqu'un sait-il comment verrouiller un objet ou une fonction afin d'empêcher la concurrence ? J'ai essayé d'ajouter un objet Lock :

private final Lock lock = new ReentrantLock();

et la ligne

boolean locked = lock.tryLock();

au début de la fonction mais cela n'a pas fonctionné.

64voto

Neil Coffey Points 13408

Afin d'appeler wait() sur un objet, vous devez détenir le verrou synchronisé sur cet objet (bien que le verrou soit en fait libéré pendant que le thread attend) :

synchronized (serverAddr) {
  serverAddr.wait();
}

Je dois admettre que pourquoi que tu veuilles faire ça me déconcerte dans ce cas...

21voto

LordOfThePigs Points 3853

Peut-être que la méthode que vous recherchez est Thread.sleep(long) ? Cette méthode permettra attendre (comme dans arrêter l'exécution du fil) pendant le temps spécifié en millisecondes avant de reprendre.

objet.wait(long) (qui est ce que vous utilisez) fait quelque chose de complètement différent. Il attend qu'un autre objet d'un autre thread le notifie (c'est-à-dire qu'il lui envoie une sorte de message de réveil), et attendra au maximum le nombre de millisecondes spécifié. Compte tenu du code que vous avez posté, je doute fortement que ce soit ce que vous voulez vraiment.

Si Thread.sleep() n'est pas ce que vous voulez, alors vous devriez utiliser le bloc synchronisé comme mentionné par les autres posters.

11voto

Apocalisp Points 22526

Je frémis toujours quand je vois ce genre de code. Faites-vous une faveur et jetez un coup d'oeil à l'article java.util.concurrent paquet.

1voto

krosenvold Points 35979

Pour éviter ce message d'erreur, utilisez le mot-clé synchronized :

synchronized(serverAddr){
  serverAddr.wait(60000);
}

1voto

uriDium Points 4401

Ce qui précède est correct. Vous pouvez utiliser un bloc de code synchronisé. Ou vous pouvez créer ce qu'on appelle un mutex. Un mutex peut en fait être n'importe quel objet. Beaucoup de gens utilisent simplement Object lui-même comme mutex. Ensuite, vous pouvez verrouiller sur le mutex. Tous les threads qui veulent y accéder doivent attendre que le thread qui détient le mutex le libère.

Il y avait aussi une suggestion d'Apocalisp. Je vous recommande également de consulter le paquet java.util.concurrent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X