2013-03-31 3 views
0

Je veux exécuter deux threads, qui partagent une méthode, pour imprimer quelque chose. Je veux ceci comme sortie:boucle de concurrence dans Java

a b a b a b 

Le premier thread imprime un 'a' et le second un 'b'. J'ai réussi à l'imprimer une fois, mais je ne peux pas inclure une boucle appropriée pour échanger les impressions.

J'ai écrit ce code pour exécuter ceci:

public void run() { 
    while(i<10) { 
     synchronized(this) { 
      while (turn!=turn) { 
       try { 
        turn=!turn; 
        wait(); 
        sleep(10); 
       } 
       catch(InterruptedException ie){} 
      } 

      printThreadOutput(); 
      turn=!turn; 
      i++; 
      notifyAll(); 
     } 
    } 
} 

Toutes les suggestions?

+8

'while (tour! = Tourner)'? –

+0

'synchronized' devrait résoudre le non-det –

+0

Votre code contient des onglets mixtes et des espaces pour l'indentation - c'est une mauvaise idée. Vous devez vous assurer d'utiliser des onglets ou des espaces de manière cohérente. – thejh

Répondre

0
  1. Faites un des threads pour dormir 5 secondes avant le moment. Cela rendra clair quel sera l'ordre des threads.
  2. La boucle while ne s'exécute pas car sa condition est toujours false. Enlevez le while complètement, vous n'en avez pas besoin.
  3. La variable turn n'est pas nécessaire. Le synchronize et le Thread.sleep(5) feront tourner les discussions.
  4. Mettez au moins quelques println lorsque vous attrapez le InterruptedException.
+0

"La synchronisation et Thread.sleep (5) feront tourner les threads". Ce n'est pas strictement vrai. La plupart des machines virtuelles exécutent un changement de contexte lorsque vous appelez 'Thread.sleep', mais il n'est pas garanti que l'autre thread s'exécutera pendant que ce thread est en veille. Vous devriez toujours avoir une variable de contrôle si vous voulez garantir ce genre de comportement. –

+0

ok! cela fonctionne très bien selon vos instructions. Merci – b10n1k

1

Une solution simple consiste à utiliser java.util.concurrent.locks.Lock, qui effectuera toutes les opérations d'attente et notifier requises:

public class ThreadTest { 

    private static final Lock lock = new ReentrantLock(); 

    public static final void main(String[] args) { 
     Runnable aRun; 
     Runnable bRun; 

     aRun = new Runnable() { 
      public void run() { 
       while (true) { 
        lock.lock(); 
        System.out.println("a"); 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         Thread.currentThread().interrupt(); 
        } 
        lock.unlock(); 
       } 
      } 
     }; 

     bRun = new Runnable() { 
      public void run() { 
       while (true) { 
        lock.lock(); 
        System.out.println("b"); 
        try { 
         Thread.sleep(1000); 
        } catch (InterruptedException e) { 
         Thread.currentThread().interrupt(); 
        } 
        lock.unlock(); 
       } 
      } 
     }; 

     Thread aThread = new Thread(aRun); 
     Thread bThread = new Thread(bRun); 
     aThread.start(); 
     bThread.start(); 
    } 

} 

Sans l'aide des moniteurs, vous pouvez le faire comme ça, mais comme @noahz souligne humblement, il utilise un Spinlock qui n'est pas aussi efficace.

public class ThreadTest { 

    private static volatile Boolean isATurn = true; 

    public static void main(String[] args) { 
     Runnable aRun; 
     Runnable bRun; 

     aRun = new Runnable() { 
      public void run() { 
       while (true) { 
        while (!isATurn) { 
        } 
        System.out.println("a"); 
        isATurn = false; 
       } 
      } 
     }; 

     bRun = new Runnable() { 
      public void run() { 
       while (true) { 
        while (isATurn) { 
        } 
        System.out.println("b"); 
        isATurn = true; 
       } 
      } 
     }; 

     Thread aThread = new Thread(aRun); 
     Thread bThread = new Thread(bRun); 
     aThread.start(); 
     bThread.start(); 
    } 

} 

Pour autant que je peux dire, cela garantit pas l'impasse, mais la famine est possible si l'un des fils ne se termine pas depuis l'autre sera en attente sur elle. Cela ne devrait pas poser de problème pour un exemple simple comme celui-ci. Les moniteurs sont également préférés à l'utilisation de l'interrogation, mais sont légèrement plus impliqués.

+0

Ugh. Verrou d'essorage occupé. – noahlz

+0

J'ai été expérimenté avec votre code aussi et c'est très utile. – b10n1k

1

Il est 3h30 du matin ici et je veux aller dormir. C'est ce que je suis venu avec:

class TurnHolder { 

    private volatile int currentTurn; 

    public void setNextTurn() { 
    this.currentTurn = currentTurn^1; 
    } 

    public int getCurrentTurn() { 
    return currentTurn; 
    } 
} 

class Printer implements Runnable { 

    private String toPrint; 
    private TurnHolder sharedResource; 
    private int turn; 

    Printer(String toPrint, TurnHolder sharedResource, int turn) { 
    this.toPrint = toPrint; 
    this.sharedResource = sharedResource; 
    this.turn = turn; 
    } 

    @Override 
    public void run() { 

    while (true) { 
     synchronized (sharedResource) { 
     if (sharedResource.getCurrentTurn() != turn) 
      try { 
      sharedResource.wait(); 
      } catch (InterruptedException e) { 
      e.printStackTrace(); 
      } 
     System.out.println(toPrint); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     sharedResource.setNextTurn(); 
     sharedResource.notifyAll(); 
     } 
    } 

    } 

Une façon de l'exécuter est:

TurnHolder sharedResource = new TurnHolder(); 

Printer printerA = new Printer("a", sharedResource, 0); 
Printer printerB = new Printer("b", sharedResource, 1); 

new Thread(printerA).start(); 
new Thread(printerB).start(); 

De cette façon, votre sharedResource gardera la mémoire du tour et la synchronisation sur elle vous permet de faire ce que vous avoir à faire avec ce tour, puis vous pouvez changer de tour. Le Thread.sleep est juste pour vous laisser voir l'impression à une bonne vitesse. printThreadOutput();

P.S .: suggestion sur la façon d'améliorer le code sont les bienvenus.