2008-10-22 7 views
1

Disons que j'ai une classe dans mon application Web appelée classe "Foo". Il a une méthode initialise() qui est appelée lorsque le bean est créé en utilisant Spring. La méthode initialise() essaie ensuite de charger un service externe et de l'assigner à un champ. Si le service n'a pas pu être contacté, le champ sera défini sur null.Java Web Application Sync Question

private Service service; 

public void initialise() { 
    // load external service 
    // set field to the loaded service if contacted 
    // set to field to null if service could not be contacted 
} 

Quand quelqu'un appelle la méthode get() de la classe « Foo » le service sera invoquée si elle a commencé dans la méthode Initialise(). Si le champ pour le service est null, je veux essayer de charger le service externe.

public String get() { 
    if (service == null) { 
     // try and load the service again 
    } 
    // perform operation on the service is service is not null 
} 

Est-il possible que je puisse avoir des problèmes de synchronisation si je devais faire quelque chose comme ça?

Répondre

1

boîte à outils La réponse est correcte. Pour résoudre le problème, déclarez simplement la méthode initialise() de votre Foo à synchroniser. Vous pouvez refactoriser Foo comme:

private Service service; 

public synchronized void initialise() { 
    if (service == null) { 
     // load external service 
     // set field to the loaded service if contacted 
    } 
} 

public String get() { 
    if (service == null) {    
     initialise(); // try and load the service again 
    } 
    // perform operation on the service is service is not null 
} 
+0

merci pour cela! bonne idée avec le refactoring;) – digiarnie

+0

C'est une forme de double-vérification de verrouillage, et donc: 1. Cela ne fonctionne qu'avec Java 5 ou plus tard. 2. "service" devrait être déclaré volatile. –

+0

Référence: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html –

0

Oui, vous aurez un problème de synchronisation.

Lets suppose que vous avez seul servlet:

public class FooServlet extends HttpServlet { 

    private MyBean myBean; 

    public void init() { 
     myBean = (MyBean) WebApplicationContextUtils. 
      getRequiredWebApplicationContext(getServletContext()).getBean("myBean"); 
    } 

    public void doGet(HttpRequest request, HttpResponse response) { 
     String string = myBean.get(); 
     .... 
    } 

} 

class MyBean { 
    public String get() { 
     if (service == null) { 
      // try and load the service again 
     } 
     // perform operation on the service is service is not null 
    } 
} 

Et votre définition de haricot ressemble:

<bean id="myBean" class="com.foo.MyBean" init-method="initialise" /> 

Le problème est que votre instance de servlet est utilisé par plusieurs threads de demande. Par conséquent, le bloc de code protégé par service == null peut être entré par plusieurs threads.

La meilleure solution (en évitant une double vérification de verrouillage, etc.) est:

class MyBean { 
    public synchronized String get() { 
     if (service == null) { 
      // try and load the service again 
     } 
     // perform operation on the service is service is not null 
    } 
} 

Hope this sens. Déposez un commentaire sinon.

+0

merci pour cela. Cependant, serait-il résolu simplement en rendant la méthode synchronisée? ou y a-t-il plus à cela alors? – digiarnie