Accion sin la interaccion del usuario

En muchas aplicaciones, surge la necesidad de realizar una determinada acción en un momento dado sin la interacción del usuario, por lo general a realizar algunas tareas administrativas. Estas tareas deben ser programadas, por ejemplo, para trabajar en las primeras horas de la mañana antes del comienzo de los negocios.
como lo hago?

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Re: Accion sin la interaccion del usuario

Que tal samuel, para poder calendarizar y ejecutar tareas en java existen muchas soluciones, desde el uso de un Timer hasta algo mas robusto. En lo particular me ha gustado mucho el framework Quartz, el cual facilmente se configura facilmente al viejo estilo de UNIX con la sintaxis de un CRON o bien puedes crear Jobs de forma programatica con la ventaja de detenerlos o monitorearlos si asi lo deseas, te dejo la liga para que le des una revisada.

Saludos

java.util.Timer

Te va a servir para realizar una programación sencilla de actividades.

Saludos

Javier Castañón

Imagen de ezamudio

Obsoleto

java.util.Timer se considera obsoleto (informalmente) a partir de Java 5 y se recomienda mejor usar java.util.concurrent.ScheduledExecutorService (lo creas con un método estático de Executors; Executors.newSingleThreadScheduledExecutor() te da algo que funciona muy similar a un Timer de Java 1.4 o anterior).

Imagen de ezamudio

Quartz

De acuerdisimo. Quartz te da mucha flexibilidad para programar tareas, porque puedes indicar a qué hora, minuto, mes, dia del mes, o dia de la semana correr una tarea, además de poder definir periodicidad, por ejemplo que algo corra cada 15 minutos pero a partir del minuto 5 de cada hora, o sea 5, 20, 35, 50.

Spring trae soporte para Quartz y me parece que trae una clase que sirve para envolver cualquier Runnable y correrlo desde dentro de Quartz (con Quartz directamente, creo que tienes que implementar una interfaz de Quartz similar a Runnable pero que trae más info de contexto del momento en que se corre).

¿Obsoleto?

No está marcado como deprecated ni siquiera en Java 6. ¿No será más bien que hay quienes opinan que es obsoleto? Yo no opino así. Si hay que ejecutar una tarea diario a la misma hora o cada cierto tiempo, es ridículamente sencillo hacerlo con java.util.Timer

Scheduling a Timer Task to Run at a Certain Time

Scheduling a Timer Task to Run Repeatedly

La misma gente de Quartz explica cuándo debería utilizarse Quartz:

of course to some simple applications these features may not be important, in which case it may then be the right decision not to use Quartz.

Saludos

Javier

Re: ¿Obsoleto?

Exacto el Timer y es muy recomendable para cosas sencillas y por desde luego que no es Obsoleto, todo depende que necesidad tengas si requieras una resortera o un cañon.

Imagen de ezamudio

Informalmente

Por eso puse que informalmente. Se considera mejor práctica usar el ScheduledServiceExecutor, que es igual de sencillo usar, simplemente lo creas y luego le pasas un Runnable indicando la frecuencia con que se debe ejecutar. Al igual que el Timer, tiene métodos para correr una tarea periódica en tiempo fijo o con retardo fijo, es decir por ejemplo que una tarea corra cada minuto sin importar si tarda 5 o 30 segundos (tiempo fijo) o que corra siempre dejando 30 segundos entre ejecuciones (se toma el tiempo a partir de que finaliza la tarea).

Executor Framework en java.util.concurrent

¡Está genial! Tienes razón es muuuucho mejor que un Timer para manejar tareas, aunque bueno, en tus mensajes sigo sin leer una sola razón más allá de "buena práctica" ;-P

Además, me pregunto si la gran mayoría de esas ventajas no son más bien en escenarios donde usar Quartz sería aún más sencillo que un Executor. En fin.

Antes, dos pequeñas correcciones, me parecen errores de dedo:

se recomienda mejor usar java.util.concurrent.ScheduledExecutorService (lo creas con un método estático de Executors; Executors.newSingleThreadScheduledExecutor()

El método estático es  

Al igual que el Timer, tiene métodos para correr una tarea periódica en tiempo fijo o con retardo fijo, es decir por ejemplo que una tarea corra cada minuto sin importar si tarda 5 o 30 segundos (tiempo fijo) o que corra siempre dejando 30 segundos entre ejecuciones (se toma el tiempo a partir de que finaliza la tarea).

Aunque dice "Al igual que Timer", éste último no tiene la capacidad de tomar el tiempo de manera relativa a partir de que finaliza una tarea, ¿o si?.

Pero lo siguiente fue lo que me abrió los ojos: ¿qué pasa si una tarea se programa para que se ejecute cada minuto y tarda más de 60 segundos su ejecución? Con un Timer retrasa a las demás, porque se usa un solo Thread. Pero con Executors, leí que puede utilizarse un Thread pool para que si una tarea tarda más de lo debido, se utilice otro Thread para continuar con el trabajo, pues es una de las ventajas sobre Timer. Hice una pequeña prueba pero no funcionó.

No quisiera secuestrar más este post, ¿les parece bien que publique aquí mismo el código de ejemplo o publico otra pregunta en el foro?

Saludos

Javier

Timer y Executor, código de ejemplo

A continuación y como apoyo a lo que dice ezamudio sobre la similitud entre Timer y unExecutor.

 

Saludos

Javier

Imagen de ezamudio

Executors

Hay principalmente dos metodos estáticos en Executors para crear los ScheduledExecutors: newSingleThreadScheduledExecutor() y newScheduledThreadPool(int), el primero como su nombre lo dice crea un ScheduledExecutor con un solo thread y el segundo crea un ScheduledExecutor que usa un thread pool del tamaño que le indiques.

El metodo Timer.schedule(TimerTask, long, long) es similar a ScheduledExecutorService.scheduleWithFixedDelay(Runnable, long, long, TimeUnit) y el Timer.scheduleAtFixedRate(TimerTask, long, long) es similar a ScheduledExecutorService.scheduleAtFixedRate(Runnable, long, long, TimeUnit).

Fixed-delay es cuando se toma el tiempo a partir de que termina la ejecución de la tarea; fixed-rate es cuando se toma el tiempo a partir de que comienza la tarea. En este último, es cuando si la tarea se tarda demasiado, las siguientes ejecuciones se van a correr de inmediato. En tu ejemplo, si la programas cada 60 segundos y la ejecución toma digamos 61 segundos, entonces en cuanto termina de correr la tarea que toma 61 segundos, se ejecuta nuevamente de inmediato y si toma sólo 10 segundos, entonces se correrá nuevamente 49 segundos después.

Yo mencioné que ScheduledExecutorService se recomienda usar en vez de java.util.Timer, pero no dije nada respecto a Quartz; Quartz ya es un framework aparte que ofrece mucha mayor flexibilidad en la programación de tareas por el estilo en que se define la periodicidad, tipo crontab. Pero sí, la ventaja mayor de ScheduledExecutorService es que puedes crear uno con un thread pool y entonces puedes programar varias tareas distintas, con distintas periodicidades, y si una está corriendo cuando ya se debe correr otra, se usa un thread separado para esta.

Re: Executors

ezamudio

el Timer.scheduleAtFixedRate(TimerTask, long, long) es similar a ScheduledExecutorService.scheduleAtFixedRate(Runnable, long, long, TimeUnit)

Esa parte me queda clara, lo que preguntaba es si estoy malinterpretando el JavaDoc, pues en tu mensaje anterior das a entender que el Timer es capaz de programar tareas con un retraso basado en la terminación de la tarea anterior:

ezamudio

Al igual que el Timer, tiene métodos para correr una tarea periódica en tiempo fijo o con retardo fijo, es decir por ejemplo que una tarea corra cada minuto sin importar si tarda 5 o 30 segundos (tiempo fijo) o que corra siempre dejando 30 segundos entre ejecuciones (se toma el tiempo a partir de que finaliza la tarea).

No hallé cómo hacer eso con un Timer. Bueno, no importaría si no supiera o pudiera, ya no voy a usar Timer en nuevo código ;-)

ezamudio:

fixed-rate es cuando se toma el tiempo a partir de que comienza la tarea. En este último, es cuando si la tarea se tarda demasiado, las siguientes ejecuciones se van a correr de inmediato

Ese es el efecto que pensé se evitaría con un pool de threads: que si una tarea programada se tarda más de lo debido las ejecuciones subsecuentes ocurrirían según la programación original en otro thread tomado del pool, pero no funciona así, inclusive el JavaDoc es claro al respecto:

 
If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.

Creo que están protegiendo al programador de posibles "race conditons". Con respecto a la ventaja de que se toma un thread del pool:

ezamudio:

Pero sí, la ventaja mayor de ScheduledExecutorService es que puedes crear uno con un thread pool y entonces puedes programar varias tareas distintas, con distintas periodicidades, y si una está corriendo cuando ya se debe correr otra, se usa un thread separado para esta.

En mi caso a cada tarea siempre le había creado su propio  , de manera que el retraso o muerte de una no afectara a otras. En este caso en particular creo que la ventaja podría un mejor manejo de recursos, vía la prevención de "thread leaks". Lo anterior aún no lo valido. Véase el siguiente código de prueba:

 

El cual me da la siguiente salida:

 

Como puede observarse, el retraso en una tarea, la que corre en Thread Timer-0 no retrasa la ejecución de la tarea que ejecuta en Thread Timer-1. Obteniendo efectivamente el mismo comportamiento que cuando se usa  .

También había leído es que si ocurría una excepción en una tarea realizada por un Executor, el framework iniciaba automáticamente otro hilo para que las tareas programadas pudieran continuar, a diferencia del   cuyo   se muere en caso de una excepción de Runtime. Pero el JavaDoc me desanima pues indica que esta funcionalidad de iniciar automáticamente un nuevo   no es soportada por ScheduledThreadPoolExecutor.scheduleAtFixedRate():

If any execution of the task encounters an exception, subsequent executions are suppressed.

El sistema está en mantenimiento y definitivamente si hubiera una buena razón podrían reemplazarse los Timers. Estoy convencido que el Executor Framework de   es muy superior para la programación de actividades que el  . Pero para el caso de Timers sencillos utilizados como lo he ejemplificado, pues no veo una sola ventaja del   sobre el   que justifique el cambio (If ain't broken, then don't fix it). ¿Qué parte no estoy entendiendo? Aclaro que las tareas programadas no son críticas, con que se ejecuten una sola vez al día dentro de un determinado intervalo de tiempo es más que suficiente, y que este razonamiento lo tengo en función del conocimiento adquirido hasta el momento.

Saludos

Javier Castañón

Imagen de ezamudio

No los cambies

Pues no los cambies; simplemente cuando hagas código nuevo ya no uses Timers, usa ScheduledExecutorService.

En cuanto a Timer y el fixed-delay: el problema es por el nombre de los métodos. En el ScheduledExecutorService ya se llaman scheduleAtFixedRate y scheduleWithFixedDelay, mientras que en el Timer tienes scheduleAtFixedRate() schedule() (que no es descriptivo, pero ése es el de fixed-delay). La razón? compatibilidad histórica. El primer Timer nada más tenía el método schedule() y lo implementaban con fixed-delay; en una versión posterior de Java ya el Timer tenía el nuevo método scheduleAtFixedRate() que ahora tenía un nombre más descriptivo, pero no quisieron agregar el scheduleWithFixedDelay() porque ya tenian schedule() y no lo quisieron renombrar para no tronar código viejo que de repente usara una nueva versión de Java (eso se hubiera solucionado con un poco de redundancia, implementando scheduleWithFixedDelay() para que simplemente invocara schedule() y ya).

Ejecutar a cierta hora todos los dias

Hola,

me podrian ayudar a como usar el timer o el executer para ejecutar a una cierta hora todos los dias, y si previamente podría comoprobar si por lo que sea el hilo anteriormente lanzado sigue ejecutandose que lo mate y vuelva a ejecutar a la hora especificada, nose si hacerlo con esto:

int numberOfMillisecondsInTheFuture = 10000; // 10 sec
Date timeToRun = new Date(System.currentTimeMillis()+numberOfMillisecondsInTheFuture);
Timer timer = new Timer();

timer.schedule(new TimerTask() {
public void run() {
// Task here ...
}
}, timeToRun);

pero no se como poner eso por ejemplo todos los dias a las 20:00 y antes compruebe si el hilo de la ultima ejecución sigue vivo lo pare y ejecute de nuevo otro.

que es preferible

buenas me gustaria saber que es preferible
un timer
o un runnable con un cliclo infinito con sleep ? saludos

Imagen de paranoid_android

El timer

El timer es mas adecuado

puedes

decirme la razon logica ???

Imagen de paranoid_android

Usar métodos del api de java

En el caso del timer contra un ciclo infinito. (Dependiendo de la necesidad y usando el criterio)
Usar un ciclo infinito con sleep es prácticamente desarrollar tu timer, salvo que necesites algo muy especifico que no lograras hacer con el api ya hecho es invertir tiempo, hacer pruebas, corregir errores, optimizar y mantener código que podrías ahorrarte.
Aun así como mencionan en el post seria más eficiente usar quartz..

y a nivel

de procesamiento y consumo de recursos cual de todos es la mejor opcio ??
muchas gracias por preguntar

Imagen de chicowed

Y como aría lo siguiente...

Hola compañeros que tal buen día quiero hacer lo siguiente tengo una función que compara la fecha actual del sistema con una fecha almacenada en una DB, Si las fechas son iguales manda un mensaje, necesito que esta comparación la haga el mi programa cada segundo, mi funcion es la siguiente, si alguien me puede auxiliar se lo agradeceria de antemano.
 

Duda

¿Y por qué cada segundo? Sólo es curiosidad.

Imagen de chicowed

podría ser cada minuto

podría ser cada minuto también, solo seria cuestion de cambiar el formato de mi fecha quitandole el  

Imagen de chicowed

lo que hago es comparar dos

lo que hago es comparar dos cadenas con formato de fecha, si elimino los segundo mi resultado seria igual, con la diferencia de que bastaria con ejecutar la funcion cada minuto.

Imagen de ezamudio

cadenas

No compares cadenas. Tanto Java como los sistemas de base de datos tienen tipos de dato para almacenar fecha, hora y fecha+hora. Usa java.sql.Timestamp en Java y usa DATETIME o TIMESTAMP o algo similar en tu base de datos. No compares cadenas.

SQL puede ayudarte (si tú escoges que así sea)

Es más conveniente que insertes la fecha como un  . Esto te permitirá utilizar funciones de fecha y hora propias de la base de datos. Por ejemplo, si utilizas MySQL como DBMS, podrías ejecutar la siguiente consulta:

 

Si no hay registros cuya hora de termino hubiese sido al menos hace un minuto, entonces regresará   o  .

Esta consulta siempre devolverá un registro (mientras no haya error).

 

Espero que esto pueda ayudarte.

~~~

Imagen de chicowed

Intente trabajar con tipo de

Intente trabajar con tipo de datos de fechas tanto en java como en mi base de datos el problema es que los datos se los muestro al ausuario de manera informativa, y les es algo complicado leer algo como esto:   a leer algo como esto  , lo unico que quiero saber es como mandar a llamar a mi función   cada minuto o segundo sin la interaccion del usuario.
Si alguien me puede auxiliar se lo agradeceria infinitamente.

Imagen de ezamudio

formats

Para eso existen formatters. Usas SimpleDateFormat para convertir un java.util.Date en una cadena con el formato que tú quieras.

Para ejecutar un método cada segundo utiliza un ScheduledExecutor. Lo hemos visto hasta el cansancio en varios posts en el foro.

Imagen de chicowed

Si he leído un poco sobre eso

Si he leído un poco sobre eso aquí en el foro y en otros foros, pero sigo sin entender como implementarlo en algún programa, como en el caso que yo planteo, no veo por donde empezar, puesto que soy nuevo en esto.
Muchas gracias de todos modos.

Imagen de chicowed

@jpaul

Que tal mi estimado, he estudiado un poco sobre lo que me aconsejaste, me gustaría que me dieras un poquito mas de información, por lo que veo tu query lo que hace es devolver la hora de termino en un intervalo de 1 minuto, pero la consulta que realizas no le entiendo, si me brindaras un poquito mas de información, ya logre insertar las fechas en la base de datos con "Timestamp", ahora lo que quiero hacer es que el programa solito compare las fechas.

Tengo un Boton llamado "Agregar" el cual realiza lo siguiente:
 
como haria para comparar la hora de Vencimiento almacenada en la DB con la hora actual del sistema cada minuto.
Mil Gracias...

Spring y Scheduled

Otra es que podrías integrar Spring en tu aplicación y usar los Schedulers. Es bastante simple puedes revisar algo de información aquí

DATE_SUB (MySQL)

 

Si no te he malinterpretado, quizás necesites una consulta como esta:

 

          ↑

La consulta anterior funciona en MySQL (para otros RDBMS, consulta la documentacion que corresponda).

Esta consulta busca registros cuya fecha de vencimiento sea menor que la fecha actual menos un minuto... Es decir, que hayan vencido hace un minuto o más... Luego se verifica si el total de esos registros es mayor que cero... lo cual quiere decir que sí existen tareas pendientes...

Esta consulta devolverá TRUE o 1 para tareas pendientes o FALSE o 0 en caso contrario.

~~~

Imagen de chicowed

Entiendo, me podrias explicar

Entiendo, me podrias explicar la parte de   eso no lo he visto,
lo que tengo es lo siguiente:
una tabla llamada "tareas" en MySQL con las siguientes columnas:
incice
creado
titulo
responsable
vencimiento
detalle

Al hacer una consulta como la que dices estas comparando valores Timestamp almacenados en "vencimiento" con la hora actual que la obtienes con "CURRENT_TIMESTAMP".

Entonces si asi, solo me faltaria implementar un executor o un timer para mandar a llamar al metodo que contenga la consulta?

Columna «virtual»

 

Sobre la parte de  , debemos primeramente echar un vistazo a la sintaxis de los SELECT en MySQL (resumida en el siguiente diagrama):

Lo anterior indica todos los elementos válidos en una sentencia SELECT para MySQL.

Si observas, « » es la parte de select_expr. Puede ser cualquier expresión válida. Por ejemplo:

 

Probablemente tu duda se debe a que en algunos libros de texto normalmente aparecen sólo los nombres de las columnas de las tablas de la clausula FROM y algunas funciones de agregación (AVG, SUM, etc.), pero no una expresión como la anterior, como si se agregase una columna "virtual" a nuestra consulta.

Para una referencia completa al respecto, visita SELECT Syntax

***

Adicionalmente, la expresión   se evalúa a un booleano, que puedes recuperar con:

 

~~~