Sigueme en Facebook Sigueme en Twitter Sigueme en Instagram Sigueme en Youtube
JC Mouse Bolivia
Index / Java / Proyectos / Evitar ejecutar un programa java más de una vez

Evitar ejecutar un programa java más de una vez

Autor jc mouse jueves, febrero 21, 2013

Cuando se hace uso de programas a veces no importa que este cree más de una instancia al mismo tiempo, por ejemplo podemos ejecutar Paint varias veces y trabajar en paralelo en varios proyectos.

Un programa hecho en java puede ejecutarse las veces que sea al mismo tiempo con tan solo hacer doble clic en los archivos JAR, esto crea una nueva instancia de la aplicación que no es más que una copia exacta del programa en memoria.  Pero en ocasiones ya sea por X o Z motivos, se trata de evitar que esto suceda y maneras hay varias, yo te presento una de ellas, la más sencilla.

Explicación.

Para evitar que se creen más de una instancia a la vez de un ejecutable *.JAR, utilizaremos un archivo *.TMP (No confundir con archivos temporales creados con createTempFile ) en donde almacenaremos un valor LONG que corresponde  al tiempo actual en milisegundos  desde el 01 de enero de 1970, 00:00:00 GMT utilizando el método getTime() del objeto Date, el valor que se obtiene es de la forma “1361471591388”.

El valor LONG obtenido se almacenara en un archivo *.TMP que se llamara “miApp.tmp“. Paralelamente se iniciara un proceso que cada cierto tiempo (20 segundos, 1 minuto, 5 minutos, etc) refrescará el valor de miApp.tmp con el tiempo actual en milisegundos, para esto se emplea el objeto “ScheduledExecutorService“.

Cuando se cree una nueva instancia del programa java, este primeramente verificara que el archivo miApp.tmp exista, si no existe, no existe una instancia del programa por tanto crea el archivo *.tmp e inicia la aplicación normalmente, si el archivo SI EXISTE, entonces supone que existe una instancia de la aplicación así que lee el valor del archivo *.tmp  y realiza una resta, el resultado de la resta dado en segundos  determinara si la instancia  del programa esta activo y por tanto no crea una nueva instancia del programa.

Cuando el programa java se cierra, se destruirá el archivo *.TMP

Si me entendieron hasta aquí, entonces una aclaración, :=D , ¿porqué actualizamos el valor del archivo miApp.tmp cada cierto tiempo?, porque puede ocurrir que el programa se cierre inesperadamente y NO se destruya el archivo temporal por tanto, cuando se trate de ejecutar el archivo *.jar, saldrá el aviso “El programa ya esta en ejecución”  hasta que el archivo tmp sea eliminado manualmente, para evitar esto, si el archivo TMP ya existe, solamente debemos restamos el valor que tiene y si el resultado es mayor al tiempo que asignamos para la actualización del archivo TMP, damos por hecho de que NO EXISTE UNA INSTANCIA de la aplicación así que creamos una.

Como parece chino lo que estoy diciendo 🙂 una imagen vale mas que mil palabras:

grafico cool

clic para ampliar

Implementamos el código en una sola clase que llamamos “Control.java”

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JOptionPane;
/**
 * @web http://www.jc-mouse.net
 * @author Mouse
 */
public class Control {

    //fichero TMP
    private String appPath = System.getProperties().getProperty("user.dir");
    private File fichero = new File( appPath + "\\miApp.tmp");    
    //tiempo en que se actualiza el fichero TMP
    private int segundos = 20;

    /** Constructor de clase */
    public Control(){};

    /**
 * Comprueba que archivo TMP exista, sino lo crea e inicia valores
 */
    public boolean comprobar()
    {           
        if ( fichero.exists() )
        {           
            long tiempo = leer();//
            long res = restarTiempo( tiempo );           
            if( res < segundos )
            {              
                JOptionPane.showMessageDialog(null,"Error: La aplicacion ya esta en ejecución.");
                return false;
            }
            else
            {        
                programar_tarea();
                return true;
            }
        }
        else// no existe fichero
        {
            crearTMP();   
            programar_tarea();
            return true;
        }            
    }

    /**
 * Lee el archivo TMP y retorna su valor 
 * @return LONG cantidad de milisegundos 
 */
    public long leer()
    {
        String linea = "0";        
        BufferedReader bufferedReader;
        try {
            bufferedReader = new BufferedReader( new FileReader( fichero ) );            
            while(bufferedReader.ready()){
                linea = bufferedReader.readLine();            
        }
        }catch (IOException e) {
            System.err.println( e.getMessage() );
        }
        return Long.valueOf(linea).longValue();
    }

    /**
 * Programa un proceso que se repite cada cierto tiempo
 */
    public void programar_tarea()
    {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate( 
            new Runnable() 
            {
                @Override
                public void run() {                   
                    crearTMP(); 
                }
              }, 1000, segundos * 1000 , TimeUnit.MILLISECONDS ); //comienza dentro de 1 segundo y luego se repite cada N segundos

    }

    /**
 * Crea un archivo TMP con un unico valor, el tiempo en milisegundos
 */
    public void crearTMP()
    {
        Date fecha=new Date();        
        try {            
            BufferedWriter writer = new BufferedWriter(new FileWriter( fichero ));                        
            writer.write(  String.valueOf( fecha.getTime() ) );                        
            writer.close();            
        } catch (IOException e) {
            System.err.println( e.getMessage() );
        }        
    }

    /**
 * Resta el tiempo expresado en milisegundos
 * @param tiempoActual el tiempo actual del sistema expresado en milisegundos
 * @return tiempo el resultado expresado en segundos
 */
    public long restarTiempo( long tiempoActual )
    {
        Date date =new Date();        
        long tiempoTMP = date.getTime();        
        long tiempo = tiempoTMP - tiempoActual;        
        tiempo = tiempo /1000;        
        return tiempo;
    }

    /**
 * Elimina el fichero TMP si es que existe
 */
    public void cerrarApp()
    {   
        if ( fichero.exists() ) { fichero.delete(); }
        System.exit(0);
    }

}//--> fin clase

 

Y para poder utilizar esta clase en nuestra aplicación, la implementamos en el MAIN

public class MiApp {

    public static void main(String[] args) {
        if( new Control().comprobar() )
        {
            new interfaz().setVisible( true );
        }        
        else
        {
            System.exit(0);
        }
    }
}

Para que al cerrar la aplicación se elimine el archivo TMP, se debe implementar el método cerrarApp() en la interfaz de nuestro programa, por ejemplo en un boton:

    private void btnCerrarActionPerformed(java.awt.event.ActionEvent evt) {
          new Control().cerrarApp();          
    }

Eso es todo

demo

Proyecto y ejemplo

Tags

Si te ha gustado podrías compartirlo o dejar un comentario. ¡Muchas gracias!
Autor: JC Mouse

Yo soy yo :) JC Mouse, Soy orgullosamente boliviano soy fundador y CEO de la web jc-Mouse.net uno de las pocas web en emprendimiento y tecnología en Bolivia.

Toda la información que encuentres en este sitio es y sera completamente gratis siempre, puedes copiar, descargar y re-publicar si así lo deseas en otros blogs o sitios web, solo te pido a cambio que dejes una referencia a esta web. Esto nos ayuda a crecer y seguir aportando. Bye

Enjoy! :)

También Te Podría Interesar

Cifrado del Cesar en C Sharp

Cifrado del Cesar en C Sharp

En criptografía, el cifrado César, también conocido como cifrado por desplazamiento, código de César o desplazamiento de...

Tangram: El rompecabezas chino

Tangram: El rompecabezas chino

El Tangram es un juego chino muy antiguo, esta compuesto por 7 piezas: un paralelogramo (romboide), un cuadrado y 5 triá...

BootChess – Ajedrez en 487 bytes

BootChess – Ajedrez en 487 bytes

Desde que se crearon los videojuegos para computadora, el espacio de almacenamiento y memoria han sido siempre un proble...

Google Open Source: Código Abierto +2000 proyectos

Google Open Source: Código Abierto +2000 proyectos

Google abre las puertas de Google Open Source un nuevo sitio web que une todos sus proyectos de “Código Abierto...

Impuestos Bolivia :: Código de Control en C#

Impuestos Bolivia :: Código de Control en C#

Hola 🙂 en esta post se deja a disposición de la comunidad de programadores  que quiera aprender un poquito sobre Factura...

Reproductor de video con VLCJ

Reproductor de video con VLCJ

VLC Media Player es un reproductor multimedia de código abierto muy popular desarrollado por el proyecto VideoLAN. VLCJ...

21 comentarios en “Evitar ejecutar un programa java más de una vez”

  1. Carlos dice:

    Gracias excelente ….

    Te queria pedir un favor .. la otra vez intente usuar un jTalkPanel juzto el mismo que pones en tu programa demo ….

    Lo agregue a la paleta trate de arraztrar pero no me acepta adicionarle los demoas Swing

    Tal vez este tema podrias tocarlo mas adelante

    Muchas gracias … por compartir tu conocimiento

    1. Mouse dice:

      :/ jTalkPanel, no lo probé con ese componente, le daré una revisada 🙂

  2. Freed dice:

    excelente aunque yo lo hago usando un puerto solo que me da problemas al usar mi metodo para iniciar y cerrar sesion en mi aplicacion pues al hacer eso como coloque que por medio de un JOptionPane me mande un aviso cuando intente abrir de nuevo el programa y cerrarlo automaticamente me salta ese aviso y me cierra la aplicacion provare este metodo y ya te comento jc mouse y una vez mas gracias por tus tutoriales. Esta claro que quien no aprende algun lenguaje de programacion es porque no quiere pues recursos hay en toda la web.

  3. Florentino dice:

    Muy util, muy buenos posts.

  4. Freed dice:

    provado y testeado, hay un pequeño pequeño detalle que ocurre rara vez y es que el archivo temporal aveces no se borra y al ejecutar la aplicacion se cierra, o pasa lo contrario el archivo igual no se borra pero al ejecutar la aplicacion deja abrirla sin problemas pero eso si, si la quiere uno volver a abrir funciona perfecto pues no permite ejecutar otra vez la aplicacion, pienso que ese detallito a de venir en el tiempo de verificacion, pues lo ejecute en una aplicacion que estoy desarrollando y paso lo mismo pero te digo es rara las veces que pasa esto, pero de ahi muchas gracias esta es otra forma mas sencilla para evitar que una aplicacion en java se ejecute mas de una vez, saludos jc mouse.

    1. Marcos_MT dice:

      me pasa igual. el programa funciona de maravilla gracias jc! pero tiene un bug: si el archivo TMP ya existe la ejecucion de la primera instancia del programa funciona perfectamente y si lo ejecuto por segunda vez entonces la segunda instancia no “corre”, hasta aqui todo bien, peeeroooo cuando cierro la aplicacion no se elimina el archivo TMP.
      obs. en el caso de que el archivo TMP no exista inicialmente todo funciona de maravilla, el TMP si se elimina al cerra la aplicacion. Ayuudaaa! grax

  5. richar16 dice:

    Buena opcion JC… Como comentario ami en lo personal me ha funcionado perfecto lo de crear un ServerSocket sobre un puerto en especifico y en los casos duplicados simplemente nunca se lograra ya que no se podra crear otro ServerSocket sobre el mismo puerto. Gracias por el aporte 🙂

  6. Rubén Soria dice:

    Muchas gracias por compartir esto, por cierto no se si solo sea yo pero al tratar de hacer la descarga me muestra un error 403.

    1. Mouse dice:

      lo siento, ya esta disponible 🙂

  7. Carlos dice:

    Para ser mas especifico es un jXTaskPane1 …de Swingx

    Creo que si lo estas utilizando en la imagen del aplicativo App

    NO se si puedas tocar este tema como usar este componente de manera VIsual jalandolo de paleta .. como te comento no funciona correctamente de esta manera no permite agregar otros componetes dentro de el

    muchas gracias

  8. Hansel dice:

    Muchísimas gracias JC, q excelente tutorial han impartido…

  9. Felipe dice:

    Gracias por publicar esta solución, me sirvió bastante.
    El único detalle es que debes definir el schudel como publico, para luego detenerlo antes de cerrar el programa, debido a que se puede dar esta situación:
    se elimina el archivo y antes de ejecutar la instrucción system.exit se ejecuta el schedule.

    public class Control {
    private ScheduledExecutorService schedule = null;
    public void programar_tarea()
    {
    scheduler = Executors.newSingleThreadScheduledExecutor();
    ….
    }

    public void cerrarApp()
    {
    schedule.shutdown(); //stop schedule
    if ( fichero.exists() ) { fichero.delete(); }
    System.exit(0);
    }


    }

    Gracias nuevamente por el codigo!!

  10. Felipe dice:

    schudel como publico
    CORRECCION!!
    COMO PRIVADO…
    y eso que lo defini como privado…

    private ScheduledExecutorService schedule = null;

  11. Hector dice:

    Hola referente a este tema luego de investigar bastante y solo encontre 2 soluciones atraves del puerto y mediante un fichero pero se me ocurio otra cosa la verdad soy nuevo programando en java, pero habia hecho algo similar en C# claro de manera mucho mas facil entonces lo q hice fue seguir la idea q tenia, de C# la cual consistia en conocer si el proceso ya se estaba ejecutando para abreviar lo q hago es conocer el id del proceso q se esta comenzando a ejecutar mediante:
    ManagementFactory.getRuntimeMXBean().getName();
    con esto utilizando el comando del sistema
    jps -l Ojo este comando
    me devuelve las app java q se estan ejecitando con una informaicon adicional entre ella el pakete y el pid o id de proceso
    con esto y como conozco el id del proceso ya se si hay mas de 1 app java q tiene un pkt o clase ejecutandose y si es asi ya cierro la app y no la ejecuto agrandes rasgos fue lo q hice hasta ahora me ha funcionado perfectamente claro no he hecho las pruebas del todo profundas, ojo es necesario q la ruta del jdk se encuentre en el path del sistema para q se pueda ejecutar el comando jps, lo q hice verifica todo esto e informa al usuario para q haga lo correspondiente es una alternativa creo espero les peuda servir la idea

    1. Mouse dice:

      buena idea, creo que tendré que robártela 🙂

  12. leonardo dice:

    Buenas muy buen codigo pues me funciona bien, pero hay un problema que cuando creo un ejecutable del archivo jar me deja de funcionar, q podria ser ???

  13. leonardo dice:

    solo para informar que ya resolvi mi problema, cuando ejecutaba mi aplicacion desde jar me creaba el archivo .tmp pero cuando lo hacia desde el intalador no lo hacia buscando encontre que otra manera de hacerlo era poniendo “user.home” en vez de “user.dir” y me funciono tanto desde el jar como desde el instaldor dandome cuenta que el archivo tmp me lo crea en el directorio de sistema de archivos del sistema operativo que contiene los archivos para un determinado usuario del sistema 🙂

  14. leonardo dice:

    BUENAS TARDES DEJE UNA PUBLICACION AQUI Y YA NO ESTA PORQUE??

  15. Cristian dice:

    Muchas gracias, me sirvio de maravilla, era exactamente lo que necesitaba!

  16. Pablo Palma dice:

    Muy buen codigo, se agradece, con este mismo cree un codigo para controlar sesiones atraves de archivo en caso de cierre inesperado.

    A veces el codigo no borra el archivo, y varios comentarios aca dicen lo mismo, dando que la siguiente ejecución a pesar de no haber otra instancia no se ejecute por error. el error es porque falta cerrar el archivo luego de leer en el método leer() :

    public long leer()
    {
    String linea = "0";
    BufferedReader bufferedReader;
    try {
    bufferedReader = new BufferedReader( new FileReader( fichero ) );
    while(bufferedReader.ready()){
    linea = bufferedReader.readLine();
    }
    bufferedReader.close();//Agregar esta linea para cerrar el archivo al leer
    }catch (IOException e) {
    System.err.println( e.getMessage() );
    }
    return Long.valueOf(linea).longValue();
    }

Los comentarios estan cerrados

Comparte lo que sabes

Categorias

Últimas entradas

El Tangram es un juego chino muy antiguo, esta compuesto por 7 piezas: un paralelogramo (romboide), un cuadrado y 5 triá...

Espresso es un framework de testing propiedad de Google que está dirigido a desarrolladores que creen que las pruebas au...

Harvard WorldMap es una plataforma de mapeo de código abierto en línea, desarrollado por el Centro de Análisis Geográfic...

Realizar pruebas sobre nuestro código nos permiten comprobar su correcto funcionamiento e integración con otros módulos...

Android Bolivia

MAUS