2010-03-08 2 views
0

J'ai un fichier JAR Java qui est déclenché par un travail du serveur SQL. Il fonctionne avec succès depuis des mois. Le processus extrait un fichier plat structuré vers une base de données intermédiaire puis pousse ces données dans un fichier XML.Qu'est-ce que je fais à propos d'un programme Java qui a engendré deux instants de lui-même?

Cependant, hier, le processus a été déclenché deux fois en même temps. Je peux dire à partir d'un fichier journal qui est créé, il semble que le processus a couru deux fois simultanément. Cela a causé beaucoup de problèmes et le fichier XML qui a été expulsé était mal formé et contenait des noeuds dupliqués, etc.

Ma question est, est-ce un problème connu avec plusieurs instances de Java JVM générant de lui-même? Ou devrais-je regarder SQL Server comme le coupable? Je suis à la recherche de «verrouillage de socket» ou de verrouillage de fichier pour éviter plusieurs instances dans le futur.

Ceci est la première occurrence de ce problème dont j'ai déjà entendu parler.

Plus d'infos:

Le travail est programmé pour exécuter toutes les minutes. Le travail déclenche un fichier .bat contenant java.exe - jar nom_fichier.jar

Le programme Java s'exécute, analyse un répertoire pour un fichier puis exécute une boucle pour traiter le fichier s'il en trouve un. Après avoir traité le fichier, il exécute une autre boucle qui envoie des messages XML.

Je peux fournir des exemples de code si cela peut aider.

Merci,

Kevin

+0

Voir http://stackoverflow.com/questions/177189/how-to-implement-a-single-instance-java-application – RichardOD

+0

Il semble que la première fois que le processus a duré plus d'une minute, c'est hier. Comme il n'a pas encore fait tout ce qu'il fait pour marquer les données traitées, la seconde instance a commencé une minute plus tard, pensant qu'il y avait du travail à faire. Les solutions de verrouillage proposées ci-dessous devraient vous aider à résoudre le problème de manière permanente. Comme solution temporaire, augmentez le temps entre les tâches à 5 ou 10 minutes. –

+0

Chris, merci pour l'entrée. J'ai cru comprendre avec les travaux Sql-Server qu'il attendra que le travail soit terminé avant de recommencer. Il tourne à 1 minute de l'heure, donc s'il court à 05:01:00 et court jusqu'à 05:02:25, il faudra attendre 05:03:00 pour courir à nouveau. J'ai l'intention de nous faire de l'une des solutions de verrouillage énumérées ici pour résoudre le problème. J'espérais comprendre un peu mieux le problème. J'ai écrit de nombreux processus comme celui-ci, et c'est la première fois que je vois le problème. – kevingreen

Répondre

3

Ce n'est pas un problème Java. Si vous voulez que l'application s'exécute seule, pas de copies, vous devez utiliser le script shell ou l'application java pour créer et supprimer un verrou quelque part.

Vous réellement commencer plusieurs Java en démarrant plus de 1 travail par lots avec la même commande. Windows et Java peuvent maintenant ce n'est pas ce que vous voulez. Vous pouvez résoudre cela par quelque chose comme:

public static void main(String [ ] args) 
{ 
    createLockIfNotExists(); 
    try { 
     yourstuff; 
    } finally { 
    releaseLock(); 
    } 
} 
private static void createLockIfNotExists() throws MyLockAlreadyExists { 
    // A bit tricky 
    // check if LOCKFILE exists, if yes throw MyLockAlreadyExists 
    // try to create LOCKFILE, can fail if at 1 ms earlier an other app created 
    // that file, so an exception while creating also results in LockAlreadyExists 
} 

Y a-t-il de bons exemples quelque part qui gèrent ce verrouillage? Peut-être dans Apache Commons?

Here semble être un exemple fonctionnel pour Windows.

Vous pouvez également utiliser la base de données pour écrire votre verrou. Verrouillez la table de verrouillage avant de l'utiliser, donc aucun processus 2 n'écrit son verrou en même temps, et lisez ensuite l'enregistrement de verrou pour vérifier si vous avez réellement le verrou. Quelque chose comme pseudo-code:

SELECT * FROM lock_table; 

if locks.length > 0: someone else is running 

LOCK lock_table; 
INSERT INTO lock_table VALUES(my_pid); 
UNLOCK lock_table; 

SELECT pid FROM lock_table; 

if pids.length > 1: what happened? 
if pids[0] != my_pid: someone else got the lock 

Un peu plus de jus et vous ajoutez également non seulement le PID, mais aussi un horodatage, et vérifier si cet horodatage est périmé (trop vieux).

+0

Merci Richard et Extaneon. Je vais essayer d'implémenter la connexion socket lock qui est référencée dans l'article auquel Richard est lié. Je pourrais essayer la technique Lockfile si la méthode socket ne fonctionne pas. Ma plus grande préoccupation est que plusieurs processus s'exécutent via des tâches SQL Server exécutant Java. Je vais créer des processus de verrouillage pour tout cela si j'ai aussi, mais je me demande toujours ce qui a causé le problème en premier lieu. D'après ce que j'ai compris, il ne pouvait être exécuté qu'une fois via le travail du serveur SQL. Mais je pourrais manquer quelque chose. Merci! – kevingreen

+0

Je devrais également mentionner que je voterais votre réponse, mais je ne peux pas encore. Je ne sais pas si vous vous souciez des points, mais je les accorderais si je le pouvais. – kevingreen

+0

Je suis d'accord que vous devez utiliser la présence d'un fichier pour verrouiller la ressource dans le cas où les deux instances sont exécutées sur des machines virtuelles Java différentes. La pratique standard sous Linux/UNIX est de placer l'identifiant de processus dans ce fichier afin qu'un humain puisse trouver le processus plus facilement. –