2014-06-17 8 views
0

Je voudrais être capable d'exécuter deux méthodes en même temps qui dépendent de la même variable globale. La première méthode met à jour périodiquement la variable partagée, mais ne finit jamais d'être exécutée. La deuxième méthode garde la trace du temps. Lorsque le temps est écoulé, la seconde méthode renvoie le dernier résultat de la variable partagée de la première méthode. Voici ce que j'ai jusqu'ici, avec pseduocode commenté dans les endroits où j'ai besoin d'aide.Partage d'un objet entre plusieurs threads java

package learning; 

public class testmath{ 
    public static void main(String[] args){ 

     long finishBy = 10000; 
     int currentresult = 0; 

     /* 
     * run eversquare(0) in a seperate thread /in parallel 
     */ 


     int finalresult = manager(finishBy); 
     System.out.println(finalresult); 
    } 


    public static int square(int x){ 
     return x * x; 
    } 

    public static void eversquare(int x){ 
     int newresult; 
     while(2 == 2){ 
      x += 1; 
      newresult = square(x); 
      /* 
      * Store newresult as a global called currentresult 
      */ 

     } 
    } 



    public static int manager(long finishBy){ 


     while(System.currentTimeMillis() + 1000 < finishBy){ 
      Thread.sleep(100); 
     } 

     /* 
     * Access global called currentresult and create a local called currentresult 
     */  
     return currentresult; 

    } 

} 
+1

Pourquoi 'while (2 == 2)' plutôt que 'while (true)'? Rappelez-vous que vous pouvez synchroniser un bloc dans une méthode, pas seulement une méthode entière. –

+2

Lisez le didacticiel sur la concurrence et essayez quelque chose: http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html –

+0

@PatriciaShanahan ils ont des valeurs booléennes équivalentes, utiliseront true dans le futur. J'ai commencé à apprendre Java il y a trois jours, pourriez-vous expliquer un peu plus ce que vous voulez dire par «vous pouvez synchroniser un bloc dans une méthode, pas seulement une méthode entière» et comment cela m'aiderait ici. – Michael

Répondre

2

Vous ne devez exécuter un fil supplémentaire:

public class Main { 
    /** 
    * Delay in milliseconds until finished. 
    */ 
    private static final long FINISH_BY = 10000; 
    /** 
    * Start with this number. 
    */ 
    private static final int START_WITH = 1; 
    /** 
    * Delay between eversquare passes in milliseconds. 
    */ 
    private static final long DELAY_BETWEEN_PASSES = 50; 
    /** 
    * Holds the current result. The "volatile" keyword tells the JVM that the 
    * value could be changed by another thread, so don't cache it. Marking a 
    * variable as volatile incurs a *serious* performance hit so don't use it 
    * unless really necessary. 
    */ 
    private static volatile int currentResult = 0; 

    public static void main(String[] args) { 
    // create a Thread to run "eversquare" in parallel 
    Thread eversquareThread = new Thread(new Runnable() { 
     @Override public void run() { 
     eversquare(START_WITH, DELAY_BETWEEN_PASSES); 
     } 
    }); 

    // make the eversquare thread shut down when the "main" method exits 
    // (otherwise the program would never finish, since the "eversquare" thread 
    // would run forever due to its "while" loop) 
    eversquareThread.setDaemon(true); 

    // start the eversquare thread 
    eversquareThread.start(); 

    // wait until the specified delay is up 
    long currentTime = System.currentTimeMillis(); 
    final long stopTime = currentTime + FINISH_BY; 
    while (currentTime < stopTime) { 
     final long sleepTime = stopTime - currentTime; 
     try { 
     Thread.sleep(sleepTime); 
     } catch (InterruptedException ex) { 
     // in the unlikely event of an InterruptedException, do nothing since 
     // the "while" loop will continue until done anyway 
     } 
     currentTime = System.currentTimeMillis(); 
    } 
    System.out.println(currentResult); 
    } 

    /** 
    * Increment the value and compute its square. Runs forever if left to its own 
    * devices. 
    * 
    * @param startValue 
    * The value to start with. 
    * 
    * @param delay 
    * If you were to try to run this without any delay between passes, it would 
    * max out the CPU and starve any other threads. This value is the wait time 
    * between passes. 
    */ 
    private static void eversquare(final int startValue, final long delay) { 
    int currentValue = startValue; 
    while (true) { // run forever (just use "true"; "2==2" looks silly) 
     currentResult = square(currentValue); // store in the global "currentResult" 
     currentValue++; // even shorter than "x += 1" 
     if (delay > 0) { 
     try { // need to handle the exception that "Thread.sleep()" can throw 
      Thread.sleep(delay); 
     } catch (InterruptedException ex) { // "Thread.sleep()" can throw this 
      // just print to the console in the unlikely event of an 
      // InterruptedException--things will continue fine 
      ex.printStackTrace(); 
     } 
     } 
    } 
    } 

    private static int square(int x) { 
    return x * x; 
    } 
} 

Je dois aussi mentionner que le mot-clé « volatile » fonctionne pour les primitives (la plupart), étant donné que toute machine virtuelle Java, vous verrez ces jours-ci garanties ils seront modifiés atomiquement. Ce n'est pas le cas pour les objets, et vous devrez utiliser des blocs et des verrous synchronisés pour vous assurer qu'ils sont toujours «vus» dans un état cohérent.

La plupart des gens mentionner aussi que vous devriez vraiment pas utiliser le mot-clé synchronized sur la méthode elle-même, et au lieu de synchroniser sur un objet « verrouiller » spécifique. Et généralement cet objet de verrouillage ne devrait pas être visible en dehors de votre code. Cela permet d'empêcher les gens d'utiliser votre code de manière incorrecte, de se mettre dans le pétrin, puis d'essayer de vous blâmer. :)

+0

Ceci est extrêmement utile. La seule chose qui ne me soit pas claire, c'est pourquoi le retard est nécessaire. Ma compréhension est que l'ajout de plusieurs threads permet au programme d'utiliser les multiples CPU d'un ordinateur. Au fur et à mesure que je lis votre code, il perd de précieux temps de calcul en désactivant la fonction pendant 50 millisecondes chaque fois qu'elle renvoie une valeur. Je suppose que cela dépend à quoi sert un programme et les différents types de machines sur lesquelles il fonctionnera. – Michael

+0

Ceci est évidemment un exemple de jouet, avec 'DELAY_BETWEEN_PASSES = 0' la fonction obtient jusqu'à 1516175360, où un délai de 50 millisecondes, il obtient seulement 40401. – Michael

+0

@Michael: Depuis Java (en théorie) peut fonctionner n'importe où, vous pouvez Ne faites aucune hypothèse sur le système d'exploitation et le processeur sous-jacents. Cela est d'autant plus vrai que de plus en plus de personnes se déploient vers «le cloud». S'il se produisait où un seul noyau est disponible, le thread eversquare pourrait absorber tellement de temps processeur, la méthode/thread 'main' pourrait ne jamais avoir assez de temps CPU pour se réveiller, ou il pourrait marcher tard. Même sur les machines qui ont plusieurs cœurs, AFAIK la JVM n'est pas obligée de les utiliser pour ses threads. Quelqu'un me corrige si je me trompe à ce sujet. –

Questions connexes