Per evitar que obrin un programa dos cops el primer que em vaig plantejar era crear un fitxer en el directori de treball del programa, de tal manera que si es tornava a engegar i ja existia aquest fitxer el programa considerava que ja hi havia una instància engegada. El fitxer s'eliminava en tancar el programa. Per desgràcia, si l'usuari apagava l'ordinador "a sac" el fitxer no s'esborrava. També si es tancava correctament el sistema operatiu però no s'havia tancat l'aplicació, a vegades tampoc s'esborrava el fitxer (perquè el sistema operatiu no tancava correctament l'aplicació).
El següent mètode que vaig utilitzar, per a evitar la problemàtica anterior, va ser obrir un port com a servidor (mitjançant un ServerSocket). Així, el que comprovava era si el port estava obert o no. Si estava obert considerava que el programa estava engegat. Però això tenia altres problemes. Un és que el port, per molt rar que fos podia estar agafat per un altre programa. Un altre és que hi ha firewalls que es queixen (i molesten a l'usuari). I, per últim, a vegades el port es tancava sol (encara no sé si era per culpa meva o per culpa d'algun timeout).
Finalment vam trobar una forma molt semblant a la primera, és a dir, mitjançant un fitxer. Consisteix en bloquejar-lo (després de crear-lo). Si es pot bloquejar, vol dir que no hi ha cap instància engegada. Si no es pot bloquejar, vol dir que sí. Perquè un cop s'ha tancat el programa (bé o malament) el fitxer es desbloqueja. Dit d'altra manera, si tanquem el programa correctament el fitxer es desbloqueja; si s'apaga l'ordinador (de la manera que sigui), en tornar-lo a engegar el fitxer estarà desbloquejat.
Aquí teniu el codi:
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.io.FileNotFoundException;
import java.io.IOException;
...
File f=new File("prova");
RandomAccessFile raf=null;
FileLock fl=null;
try
{
f.createNewFile();
raf = new RandomAccessFile("prova", "rw");
FileChannel fc=raf.getChannel();
fl=fc.tryLock();
} catch (FileNotFoundException ex)
{
ex.printStackTrace();
} catch (IOException ex)
{
ex.printStackTrace();
}
if(fl==null)
{
System.out.println("Està bloquejat");
System.exit(0);
}else
{
System.out.println("Continuar");
}
La part que ens interessa, sobretot, és la linia fc.tryLock(). El mètode tryLock() de la classe FileChannel intenta bloquejar el fitxer. Si ho aconsegueix ens retorna una instància de la classe FileLock; en cas contrari ens retorna null i, per tant, sabem que el fitxer està bloquejat.


1 comentaris:
manera original d'implemenar el singleton pattern
Publica un comentari