2017-05-16 1 views
0

J'essaie d'utiliser notify() et wait(). Voici ma classe désirée. J'ai un problème, quand j'essaie d'appeler addNewItem(). Si j'appelle le tryToReadItem() d'abord, puis appelez la méthode addNewItem(), ce journal ne sera pas imprimé. Notez que mon DemoClass est le singleton.La méthode notify() d'Android n'est pas appelée

public class DemoClass { 

private static final String TAG = "DemoClass"; 

private static DemoClass instance; 
private Object lock = new Object(); 
private static Thread executor; 
private static Runnable reader; 
static MyQueue queue; 


private DemoClass() { 
    queue = MyQueue.getInstance(); 
    reader = new Runnable() { 

     @Override 
     public void run() { 
      tryToReadRequest(); 
     } 
    }; 

} 

public static DemoClass getInstance() { 
    if (null == instance) { 
     instance = new RequestExecutor(); 
     executor = new Thread(reader); 
     executor.run(); 
    } 
    return instance; 
} 

public boolean addNewItem() { 
    synchronized (lock) { 
     lock.notify(); // executor will be run 
     Log.i(TAG, "executor run..."); 
    } 
    return true; 
} 

public void tryToReadItem() { 

    try { 
     while (true) { 
      synchronized (lock) { 
       if (queue.checkTopValue() == null) { 
        Log.v(TAG, "queue is empty"); 
        lock.wait(); 
       } else { 
        //TODO other code... 
       } 

      } 
     } 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 
} 

est ici l'utilisation de cette classe:

DemoClass executor = DemoClass.getInstance(); 
boolean bool = executor.addNewItem(); 

Suis-je manque quelque chose?

Modifier: Je viens de changer mon code. Maintenant tryToReadRequest() est exécuté en continu alors que la file d'attente n'est pas vide. mais mon problème est que la ligne lock.notify(); ne s'exécute pas.

+0

Tout est dans le même fil. Il devrait y avoir un autre thread impliqué. – Enzokie

+0

Je suppose que si vous changez notifier à notifyAll vous avez le même résultat, non? – DEADMC

+0

Ce n'est pas lié à votre problème, mais pour un singleton correct, vous avez besoin d'un bloc synchronisé dans getInstance() et e.printStackTrace(); ne fonctionne pas dans Android, vous devez écrire Log.e ("tag", Log.getStackTraceString (e)) à la place – DEADMC

Répondre

0

Il y a beaucoup de problèmes avec ce code

d'abord

 if (queue.checkTopValue() == null) { 
      Log.v(TAG, "queue is empty"); 
      lock.wait(); 
     } 

Dépend official documentation

Remarque: appeler toujours attendre dans une boucle qui vérifie l'état étant attendu pour. Ne supposez pas que l'interruption était pour la condition particulière que vous attendiez, ou que la condition est toujours vraie.

Votre DemoClass est Singleton. Mais pas thread-safeSingleton

parce que plusieurs threads peuvent passer null == état de l'instance au même temps

if (null == instance) { 
     instance = new RequestExecutor(); 
     executor = new Thread(reader); 
     executor.run(); 
    } 

droit chemin est vérification supplémentaire dans le bloc synchronisé et en utilisant par exemple volatile.

donc ajouter volatile exemple

private static volatile DemoClass instance; 

et réécrivez méthode getInstance() à quelque chose comme ça

public static DemoClass getInstance() { 
    DemoClass localInstance = instance; 

    if (localInstance == null) { 
     synchronized (DemoClass.class) { 
      localInstance = instance; 
      if (localInstance == null) { 
       localInstance = new DemoClass(); 
       instance = localInstance; 
       executor = new Thread(reader); 
       executor.run(); 
      } 
     } 
    } 
    return localInstance; 
} 

note, vous pouvez laisser uniquement bloc de contrôle synchronisé à l'intérieur, mais qui fera méthode getInstance trop lent.