Right now my program accepts an input, and formats it into a Date. But I want it to call a method whenever that date is reached. How could I do this without the use of any libraries like Quartz?
Code I have for the input:
Date date = new Date();
String inputDate;
month = (String) comboBoxMonth.getSelectedItem();
day = Integer.parseInt((String) comboBoxDay.getSelectedItem());
hours = Integer.parseInt((String) comboBoxTimeH.getSelectedItem());
minutes = Integer.parseInt((String) comboBoxTimeM.getSelectedItem());
try {
//Month/Day/Year Hour:minute:second
inputDate = month + "/" + day + "/" + year + " " + hours + ":" + minutes;
date = formatter.parse(inputDate);
} catch (ParseException e) {
e.printStackTrace();
}
You can use Timer and TimerTask object.
Timer timer = new Timer ();
TimerTask myTask = new TimerTask () {
#Override
public void run () {
// call your method here
}
};
// Schedule the task. Start it when your date is reached!
timer.schedule(myTask, yourDate);
Timer object allow you to handle multiple TimerTask instance!
After the line where you parse the date, add t.schedule(task, date), where 't' is a Timer, and 'task' is a TimerTask that represents the method you want to be executed at the given date.
The Timer class mentioned in another Answer is the old way.
Executor
As of Java 5, the modern way is the Executors suite of interfaces and classes, specifically the ScheduledExecutorService.
Be sure to read up, including searching StackOverflow for more info. Specifically, be aware that any uncaught exception bubbling up to your main code running in the Executor will cause service to cease. Any future scheduled runs of your code will be terminated. The solution is simple: Always surround the main code of your executor with a try-catch to catch any Exception (and maybe even Error, or, Throwable).
Never Use Timer In Servlet/JaveEE
Most especially, do not use Timer in a Servlet or Java EE (Enterprise Edition) app. See this Answer by BalusC for details.
Related
I have a scheduler(using #Scheduler) running between 7 to 9 PM for every 15 mins. It looks for a file every 15 mins. If the file is found then the scheduler should stop for today and run next day again. How to achieve this in spring boot?
Probably the easiest way is to implement it at the level of business logic.
Spring provides a way to run a periodic task, that's true, but it can't stop the job for some time if a business case is met (the file is found).
Having said that, you could implement the scheduled job as follows:
#Component
public class MyScheduledJob {
private LocalDateTime runNextTime = null;
private boolean isFileFound = false;
#Scheduled(/**here comes your original cron expression: 7 am to 9 pm with an interval of 15 minutes as you say **/)
public void runMe() {
if(isFileFound && LocalDateTime.now().isBefore(runNextTime)) {
// do not run a real job processing
return;
}
isFileFound = checkWhetherFileExists();
if(isFileFound) {
runNextTime = calculateWhenDoYouWantToStartRunningTheActualJobProcessingNextTime();
}
... do actual job processing... Its not clear from the question whether it should do something if the file is not found as well, but I'm sure you've got the point ...
}
}
Since the bean is a singleton you can safely create a state for it, no-one won't change that state anyway.
You can do something like this. You can write your logic for checking files inside this method.
#Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void scheduleFixedRateWithInitialDelayTask() {
long now = System.currentTimeMillis() / 1000;
System.out.println(
"Fixed-rate task with one-second initial delay - " + now);
}
See this for more details.
I’m currently using selenium in a web bot to purchase items on a website. When I search for the item I want to buy and it cannot be found I use driver.navigate().refresh() to refresh the page to see if it is there now, it will keep doing this until it finds the product when it is released on the page. However, I wish to start my bot a few hours before the release of the product which currently doesn’t work as after roughly 30 seconds of refreshing the page I get banned from the page due to the anti-ddos software they use. One option is to increase the delay between refreshing, however I need to catch the release of this product as soon as possible so I’m trying to find a way that my program can wait/sleep until 30 seconds before the release however I’m struggling to find a way to do this.
Just call Thread.sleep with the appropriate amount of milliseconds:
public static void main(String[] args) throws InterruptedException {
long currentTime = System.currentTimeMillis();
long releaseTime = currentTime + 1000 * 60 * 60 * 24 * 3; // 3 days
Thread.sleep(releaseTime - currentTime);
}
Another way would be to use java.time classes:
public static void main(String[] args) throws InterruptedException {
LocalDateTime now = LocalDateTime.now();
LocalDateTime release = LocalDateTime.of(2019, 10, 30, 13, 30);
long sleepDuration = Duration.between(now, release).toMillis();
TimeUnit.MILLISECONDS.sleep(sleepDuration);
}
Java 9 introduces new methods to the Duration class like toSeconds(), toMinutes() and so on.
You could also consider using a ScheduledExecutorService to schedule your tasks. This is especially useful if you have multiple tasks to schedule and don't want having multiple threads being blocked for that:
private static final ScheduledExecutorService service = new ScheduledThreadPoolExecutor(2);
private static ScheduledFuture<?> scheduleTask(Runnable task, LocalDateTime releaseTime) {
Duration duration = Duration.between(LocalDateTime.now(), releaseTime);
return service.schedule(task, duration.toSeconds(), TimeUnit.SECONDS);
}
In general, to sleep until the next Thursday at 10:59 you could use the following code:
LocalDateTime release = LocalDateTime.now()
.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY))
.withHour(10)
.withMinute(59);
Duration duration = Duration.between(LocalDateTime.now(), release);
TimeUnit.MILLISECONDS.sleep(duration.toMillis());
I think rather than sleeping you should take a look at scheduled tasks with cron expressions in Spring... that way you don't have a blocked thread just sitting there.
Scheduled Tasks with Spring
Cron Expressions
I have a scheduled job which runs every 100 seconds. Sometimes the execution of this method takes a lot of time (which is ok and there is no problem with that). In this situation, the result of the running method is not important to me and I want to re-schedule the job for next 100 second.
What is the best way to force the running job to terminate (return) after a specific time?
My scheduled code is like below:
#Scheduled(fixedDelay = 100*1000)
fun calculateLastDaysStatistics() {
logger.info("affiliate statistics thread Started Successfully")
val processStartDate = Date()
for (i in 1..prevDaysToConsider) {
logger.info("AdZone-Stats prev days $i")
val yesterday = DateUtility.addDay(Date(), -i)
val startDate = DateUtility.getZeroDayTime(yesterday.time)
val endDate = DateUtility.addDay(startDate, 1)
/* This method is probable to take a lot of time */
calculateStatistics(startDate, endDate)
}
val processLength = (Date().time - processStartDate.time) / 1000
logger.info("affiliate statistics thread finished in " + processLength + "s")
}
Thanks.
Try using Fixed Rate instead of Fixed Delay
Here is the article from
Paraschiv.E. The #Scheduled Annotation in Spring. Referred from https://www.baeldung.com/spring-scheduled-tasks
Schedule a Task at a Fixed Rate
#Scheduled(fixedRate = 1000)
public void scheduleFixedRateTask() {
System.out.println(
"Fixed rate task - " + System.currentTimeMillis() / 1000);
}
Note that the beginning of the task execution doesn’t wait for the completion of the previous execution.
This option should be used when each execution of the task is independent.
You can implement a custom Task scheduler using, org.springframework.scheduling.TaskScheduler instead of Annotation based method.
private final TaskScheduler scheduler;
#Autowired
public SchedulingManager(TaskScheduler scheduler) {
this.scheduler = scheduler;
}
In this case,
ScheduledFuture scheduledeFuture = scheduler.schedule(()->{
....You job goes here..
}, new CronTrigger("*/100 * * * * *"));
You can keep track of the scheduled future to make sure it runs max time intended.
scheduledeFuture.get(100,TimeUnit.SECONDS)
I have the following code in my class
private static final SimpleDateFormat SDF_ISO_DATE = new SimpleDateFormat("yyyy-MM-dd");
private static final SimpleDateFormat SDF_ISO_TIME = new SimpleDateFormat("HH:mm:ss");
public static String getTimeStampAsString(final long time) {
TimeZone tz = TimeZone.getTimeZone("UTC");
SDF_ISO_DATE.setTimeZone(tz);
SDF_ISO_TIME.setTimeZone(tz);
return SDF_ISO_DATE.format(
new Date(time)) + " " + SDF_ISO_TIME.format(new Date(time)
);
}
In my multi threaded application the following method returns date in future, even for the current date, is the static method or variable is responsible for this?
edit:
I had the following code to reproduce and prove what are mentioned in the answers,but still not able to.Can some one help me for the same.
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<String> task = new Callable<String>(){
public String call() throws Exception {
return DateUtil.getTimeStampAsString(1524567870569L);
}
};
//pool with 50 threads
ExecutorService exec = Executors.newFixedThreadPool(50);
List<Future<String>> results = new ArrayList<Future<String>>();
//perform 10 date conversions
for(int i = 0 ; i < 50 ; i++){
results.add(exec.submit(task));
}
exec.shutdown();
//look at the results
for(Future<String> result : results){
System.out.println(result.get());
}
}
is the static method or variable is responsible for this?
Static variables. SimpleDateFormat isn't thread-safe, which should be obvious since you're modifying its internal state by calling setTimeZone(). It means that several threads could be doing that at the same time, which should feel like producing unpredictable results.
You need to build your formats locally rather than reuse some defined statically. Or better yet, drop Java's old time-managing classes and use java.time.* instead.
As an answer to your edit: how to reproduce the problem with thread-unsafety (not sure whether that really ought to be a separate question). Formatting the same date in two or more threads using the same SimpleDateFormat seems to go well (at least most often, no guarantee that it always will). Try formatting different date-times, and it will be very easy to get wrong results. I changed your task like this:
AtomicLong time = new AtomicLong(1_524_567_870_569L);
Callable<String> task = new Callable<String>(){
#Override
public String call() {
return DateUtil.getTimeStampAsString(time.getAndAdd(2_768_461_000L));
}
};
It’s easiest to see that the results are wrong when I also sort them in the output, so I have done that. I am only quoting the first few results from one run since this is enough to demonstrate the problem:
2018-04-24 11:04:30
2018-05-26 12:05:31
2018-06-11 13:06:32
2018-07-29 14:07:33
2018-08-08 15:08:34
2018-10-01 16:09:35
…
The expected result was (obtained by declaring getTimeStampAsString() synchronized; also sorted afterward):
2018-04-24 11:04:30
2018-05-26 12:05:31
2018-06-27 13:06:32
2018-07-29 14:07:33
2018-08-30 15:08:34
2018-10-01 16:09:35
…
Already the fifth printed result has the day-of-month all wrong, 08 instead of 30, and there are many more errors in the full list. You may try it yourself. As you probably know, exact results are not reproducible, but you should get results that are wrong somehow.
PS Here’s my code for printing the results in sorted order in case you want to try it:
//look at the results
SortedSet<String> sorted = new TreeSet<>();
for (Future<String> result : results){
sorted.add(result.get());
}
sorted.forEach(System.out::println);
tl;dr
To capture the current moment and generate a string in your desired format (which is a modified form of standard ISO 8601 format), use the java.time classes. These classes are much simpler and vastly better designed. They are also thread-safe.
Instant.now().toString().replace( "T" , " " )
Current moment
Your method is named getCurrentTimeStamp(final Date date) yet you are passing an existing Date object set to a specific moment rather than capturing the current moment.
Nowhere in your code do I see you capturing the current moment. If you want the current moment, call Instant.now() as shown below.
Avoid legacy date-time classes
The legacy date-time classes such as Date & SimpleDateFormat are not thread-safe. One of many reasons to avoid these troublesome classes. They were supplanted years ago by the java.time classes.
java.time
As a moment in UTC, the java.util.Date class is replaced by the Instant class. Same idea, but Instant has a resolution in nanoseconds rather than milliseconds. And Instant::toString does not inject a time zone dynamically as Date::toString does.
To capture the current moment in UTC, call the static Instant.now() method.
Instant instant = Instant.now() ; // Capture current moment in UTC.
Parse your input number as a count of milliseconds since the epoch reference of first moment of 1970 in UTC.
Instant instant = Instant.ofEpochMilli( 1_524_567_870_569L ) ;
instant.toString(): 2018-04-24T11:04:30.569Z
No need for must of your code. No need for your DateUtil, as seen in code above. No need for custom formatting patterns, as your desired format happens to comply with the ISO 8601 standard used by default in the java.time classes. If the T in the middle bothers you or your users, replace with a SPACE.
String output = instant.toString().replace( "T" , " " ) ;
2018-04-24T11:04:30.569Z
ExecutorService blocking
You seem to misunderstand ExecutorService::shutdown. That method does not block to wait for tasks to complete. As your code is written, some tasks may not yet be done running until after you report results (partially-completed results).
Add a call to ExecutorService::awaitTermination, as seen in code below. Set a time-out long enough that if exceeded it must mean some problem occurred. To quote the doc:
Block until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
See example code below. For more discussion see this Question, ExecutorService - How to wait for completition of all tasks in non-blocking style
Threads
The java.time classes are thread-safe by design. They use the immutable objects pattern, returning fresh object based on existing values rather than changing (“mutating”) the original.
Example code. Your Question is confused about whether you want a hard-coded moment or the current moment. Switch to either by enabling the commented-out line in this example.
Callable < String > task = new Callable < String >() {
public String call () throws Exception {
long threadId = Thread.currentThread().getId();
// String moment = Instant.ofEpochMilli( 1524567870569L ).toString().replace( "T" , " " );
String moment = Instant.now().toString().replace( "T" , " " );
String output = ( moment + " | " + threadId );
return output;
}
};
// Pool with 5 threads
ExecutorService exec = Executors.newFixedThreadPool( 5 );
List < Future < String > > results = new ArrayList < Future < String > >();
// Perform a certain number of tasks.
int countAssignedTasks = 500;
for ( int i = 0 ; i < countAssignedTasks ; i++ ) {
results.add( exec.submit( task ) );
}
// Wait for tasks to complete.
Boolean completedBeforeTimeOut = null;
try {
exec.shutdown();
completedBeforeTimeOut = exec.awaitTermination( 5 , TimeUnit.SECONDS ); // Block until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
} catch ( InterruptedException e ) {
e.printStackTrace();
}
// Report results.
System.out.println( "completedBeforeTimeOut: " + completedBeforeTimeOut );
for ( Future < String > result : results ) {
try {
System.out.println( result.get() );
} catch ( InterruptedException e ) {
e.printStackTrace();
} catch ( ExecutionException e ) {
e.printStackTrace();
}
}
System.out.println( "BASIL - done." );
When run.
Note that the times are not chronological. In multi-threaded code, you cannot predict which tasks will be executed when.
2018-04-24 20:24:06.991225Z | 13
2018-04-24 20:24:06.991246Z | 14
2018-04-24 20:24:06.991236Z | 15
2018-04-24 20:24:06.991232Z | 16
2018-04-24 20:24:06.991222Z | 17
2018-04-24 20:24:07.067002Z | 16
2018-04-24 20:24:07.067009Z | 17
tz is effectively constant and the setters don't do anything after the first invocation of either method. Use a static initialiser to set the timezone right away to make the methods thread-safe.
private static final SimpleDateFormat SDF_ISO_DATE = new SimpleDateFormat("yyyy-MM-dd");
private static final SimpleDateFormat SDF_ISO_TIME = new SimpleDateFormat("HH:mm:ss");
static {
TimeZone tz = TimeZone.getTimeZone("UTC");
SDF_ISO_DATE.setTimeZone(tz);
SDF_ISO_TIME.setTimeZone(tz);
}
public static String getCurrentTimeStamp(final Date date) {
return SDF_ISO_DATE.format(date) + " " + SDF_ISO_TIME.format(date);
}
public static String getTimeStampAsString(final long time) {
return getCurrentTimeStamp(new Date(time));
}
I need to execute a task every 5 minutes on my server to update some datas on a db, i've found that on openshift i have the cron that executes some script every tot time. Is it possibile to make a script that makes a simple call to a servlet or to a java code to run this job?
I am quite new to server side programming so please speak easy!
Ps. I am using a Tomcat 6 (Jboss EWS 1.0), mySQL 5.5 server
AS I understand you, you need your application to run sth every XX minutes.
To calculate the start time I made a helper function "getStartTime" With that I can use the human readable time like "23:30" (attention, I am from german, so it is not for AM/PM, just change for your needs).
Helper Method:
private static long getStartTime(String startTime) {
int hour = Integer.parseInt(startTime.split(":")[0]);
int minutes = Integer.parseInt(startTime.split(":")[1]);
Calendar cal = Calendar.getInstance();
Date dateNow = cal.getTime();
cal.set(Calendar.HOUR_OF_DAY, hour);
cal.set(Calendar.MINUTE, minutes);
cal.set(Calendar.SECOND, 0);
if(cal.getTime().before(dateNow)) {
cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH) + 1);
return cal.getTime().getTime();
} else {
return cal.getTime().getTime();
}
}
Now you can use the ScheduledExecutorService from Java. Example:
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
long startClearRequests = getStartTime(DEFAULT_JOB_START_TIME) - System.currentTimeMillis();
And set your needs into the scheduleAtFiexed Rate:
scheduledExecutorService.scheduleAtFixedRate(clearRequests, startClearRequests, Math.round(DEFAULT_JOB_PERIOD_HOURS * 60 * 60 * 1000), TimeUnit.MILLISECONDS);
For example I use:
private static final int NUM_OF_THREADS = 2;
private static final String DEFAULT_JOB_START_TIME = "23:30";
private static final double DEFAULT_JOB_PERIOD_HOURS = 24;
As you see, you can change the number of threads (depends of what your application is doing), the start time (this is just needed for application start (when to start the job the first time).
And also the period (every XX hour the job shall run ... I took hours, but you need ti insert milliseconds at the end, so for 5 minutes (you have to tak 5 * 60 *1000 miliseconds.
Greetings
EDIT in respect to the athors comments:
To start things on application start, you have several methods. One method is to start a servlet on startup like this. Insert into the web.xml
<servlet>
<servlet-name>ServletStartups</servlet-name>
<servlet-class>model.initialization.ServletStartups</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
This will call the Class ServletStartups on Application start (the number in load-on-startup is the priority, because you can have multiple entries and can decide which to start first (1, 2, 3 ...)
Now within your servlet you defines an init() method, which is automatically called, like that:
public class ServletStartups extends HttpServlet{
public void init() throws ServletException{
// HEre you can put your methods as described above //(scheduledExecutorService( ...
}
}
IMPORTANT NOTE:
above I had a method "clearRequests", sorry this was my method, I have not renamed it to add it here. THis method will be called in my application every 24 hours.
the methods you call from the ScheduledExecutorService have to be a callable, like this:
private Runnable clearRequests = new Runnable() {
public void run() {
try {
// Here do your task
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};