当前位置:文档之家› Java应用程序中定时执行任务

Java应用程序中定时执行任务

Java应用程序中定时执行任务
Java应用程序中定时执行任务

所有类型的Java 应用程序一般都需要计划重复执行的任务。企业应用程序需要计划每日的日志或者晚间批处理过程。一个J2SE 或者J2ME 日历应用程序需要根据用户的约定计划闹铃时间。不过,标准的调度类Timer 和TimerTask 没有足够的灵活性,无法支持通常需要的计划任务类型。在本文中,Java 开发人员Tom White 向您展示了如何构建一个简单通用的计划框架,以用于执行任意复杂的计划任务。

我将把java.util.Timer 和java.util.TimerTask 统称为Java 计时器框架,它们使程序员可以很容易地计划简单的任务(注意这些类也可用于J2ME 中)。在Java 2 SDK, Standard Edition, Version 1.3 中引入这个框架之前,开发人员必须编写自己的调度程序,这需要花费很大精力来处理线程和复杂的Object.wait() 方法。不过,Java 计时器框架没有足够的能力来满足许多应用程序的计划要求。甚至一项需要在每天同一时间重复执行的任务,也不能直接使用Timer 来计划,因为在夏令时开始和结束时会出现时间跳跃。

本文展示了一个通用的Timer 和TimerTask 计划框架,从而允许更灵活的计划任务。这个框架非常简单——它包括两个类和一个接口——并且容易掌握。如果您习惯于使用Java 定时器框架,那么您应该可以很快地掌握这个计划框架。

计划单次任务

计划框架建立在Java 定时器框架类的基础之上。因此,在解释如何使用计划框架以及如何实现它之前,我们将首先看看如何用这些类进行计划。

想像一个煮蛋计时器,在数分钟之后(这时蛋煮好了)它会发出声音提醒您。清单1 中的代码构成了一个简单的煮蛋计时器的基本结构,它用Java 语言编写:

清单1. EggTimer 类

EggTimer 实例拥有一个Timer 实例,用于提供必要的计划。用start() 方法启动煮蛋计时器后,它就计划了一个TimerTask,在指定的分钟数之后执行。时间到了,Timer 就在后台调用TimerTask 的start() 方法,这会使它发出声音。在取消计时器后这个应用程序就会中止。

计划重复执行的任务

通过指定一个固定的执行频率或者固定的执行时间间隔,Timer 可以对重复执行的任务进行计划。不过,有许多应用程序要求更复杂的计划。例如,每天清晨在同一时间发出叫醒铃声的闹钟不能简单地使用固定的计划频率86400000 毫秒(24 小时),因为在钟拨快或者拨慢(如果您的时区使用夏令时)的那些天里,叫醒可能过晚或者过早。解决方案是使用日历算法计算每日事件下一次计划发生的时间。而这正是计划框架所支持的。考虑清单2 中的AlarmClock 实现:

清单2. AlarmClock 类

注意这段代码与煮蛋计时器应用程序非常相似。AlarmClock 实例拥有一个Scheduler (而不是Timer)实例,用于提供必要的计划。启动后,这个闹钟对SchedulerTask (而不是TimerTask)进行调度用以发出报警声。这个闹钟不是计划一个任务在固定的延迟时间后执行,而是用DailyIterator

类描述其计划。在这里,它只是计划任务在每天上午7:00 执行。下面是一个正常运行情况下的输出:

DailyIterator 实现了ScheduleIterator,这是一个将SchedulerTask 的计划执行时间指定为一系列java.util.Date 对象的接口。然后next() 方法按时间先后顺序迭代Date 对象。返回值null 会使任务取消(即它再也不会运行)——这样的话,试图再次计划将会抛出一个异常。清单 3 包含ScheduleIterator 接口:

清单3. ScheduleIterator 接口

DailyIterator 的next() 方法返回表示每天同一时间(上午7:00)的Date 对象,如清单 4 所示。所以,如果对新构建的next() 类调用next(),那么将会得到传递给构造函数的那个日期当天或者后面一天的7:00 AM。再次调用next() 会返回后一天的7:00 AM,如此重复。为了实现这种行为,DailyIterator 使用了java.util.Calendar 实例。构造函数会在日历中加上一天,对日历的这种设置使得第一次调用next() 会返回正确的Date。注意代码没有明确地提到夏令时修正,因为Calendar 实现(在本例中是GregorianCalendar)负责对此进行处理,所以不需要这样做。

清单4. DailyIterator 类

实现计划框架

在上一节,我们学习了如何使用计划框架,并将它与 Java 定时器框架进行了比较。下面,我将向您展示如何实现这个框架。除了清单 3 中展示的ScheduleIterator 接口,构成这个框架的还有另外两个类—— Scheduler 和SchedulerTask 。这些类实际上在内部使用 Timer 和 SchedulerTask,因为计划其实就是一系列的单次定时器。清单 5 和 6 显示了这两个类的源代码:

清单 5. Scheduler

清单 6 显示了 SchedulerTask 类的源代码:

就像煮蛋计时器,Scheduler 的每一个实例都拥有 Timer 的一个实例,用于提供底层计划。Scheduler 并没有像实现煮蛋计时器时那样使用一个单次定时器,

它将一组单次定时器串接在一起,以便在由 ScheduleIterator 指定的各个时间执行 SchedulerTask 类。

考虑 Scheduler 上的 public schedule() 方法——这是计划的入口点,因为它是客户调用的方法(在取消任务一节中将描述仅有的另一个 public 方法cancel())。通过调用 ScheduleIterator 接口的 next(),发现第一次执行SchedulerTask 的时间。然后通过调用底层 Timer 类的单次 schedule() 方法,启动计划在这一时刻执行。为单次执行提供的 TimerTask 对象是嵌入的SchedulerTimerTask 类的一个实例,它包装了任务和迭代器(iterator)。在指定的时间,调用嵌入类的 run() 方法,它使用包装的任务和迭代器引用以便重新计划任务的下一次执行。reschedule() 方法与 schedule() 方法非常相似,只不过它是 private 的,并且执行一组稍有不同的 SchedulerTask 状态检查。重新计划过程反复重复,为每次计划执行构造一个新的嵌入类实例,直到任务或者调度程序被取消(或者 JVM 关闭)。

类似于 TimerTask,SchedulerTask 在其生命周期中要经历一系列的状态。创建后,它处于 VIRGIN 状态,这表明它从没有计划过。计划以后,它就变为SCHEDULED 状态,再用下面描述的方法之一取消任务后,它就变为 CANCELLED 状态。管理正确的状态转变——如保证不对一个非 VIRGIN 状态的任务进行两次计划——增加了 Scheduler 和 SchedulerTask 类的复杂性。在进行可能改变任务状态的操作时,代码必须同步任务的锁对象。

取消任务

取消计划任务有三种方式。第一种是调用 SchedulerTask 的 cancel() 方法。这很像调用 TimerTask 的 cancel()方法:任务再也不会运行了,不过已经运行的任务仍会运行完成。 cancel() 方法的返回值是一个布尔值,表示如果没有调用 cancel() 的话,计划的任务是否还会运行。更准确地说,如果任务在调用cancel() 之前是 SCHEDULED 状态,那么它就返回 true。如果试图再次计划一个取消的(甚至是已计划的)任务,那么 Scheduler 就会抛出一个IllegalStateException。

取消计划任务的第二种方式是让 ScheduleIterator 返回 null。这只是第一种方式的简化操作,因为 Scheduler 类调用 SchedulerTask 类的 cancel()方法。如果您想用迭代器而不是任务来控制计划停止时间时,就用得上这种取消任务的方式了。

第三种方式是通过调用其 cancel() 方法取消整个 Scheduler。这会取消调试程序的所有任务,并使它不能再计划任何任务。

扩展 cron 实用程序

可以将计划框架比作 UNIX 的 cron 实用程序,只不过计划次数的规定是强制性而不是声明性的。例如,在 AlarmClock 实现中使用的 DailyIterator 类,它

的计划与 cron 作业的计划相同,都是由以 0 7 * * * 开始的 crontab 项指定的(这些字段分别指定分钟、小时、日、月和星期)。

不过,计划框架比 cron 更灵活。想像一个在早晨打开热水的HeatingController 应用程序。我想指示它“在每个工作日上午 8:00 打开热水,在周未上午 9:00 打开热水”。使用 cron,我需要两个 crontab 项(0 8 * * 1,2,3,4,5 和 0 9 * * 6,7)。而使用 ScheduleIterator 的解决方案更简洁一些,因为我可以使用复合(composition)来定义单一迭代器。清单 7 显示了其中的一种方法:

清单 7. 用复合定义单一迭代器

RestrictedDailyIterator 类很像DailyIterator,只不过它限制为只在一周的特定日子里运行,而一个CompositeIterator 类取得一组ScheduleIterators,并将日期正确排列到单个计划中。

有许多计划是cron 无法生成的,但是ScheduleIterator 实现却可以。例如,“每个月的最后一天”描述的计划可以用标准Java 日历算法来实现(用Calendar 类),而用cron 则无法表达它。应用程序甚至无需使用Calendar 类。在本文的源代码(请参阅参考资料)中,我加入了一个安全灯控制器的例子,它按“在日落之前15 分钟开灯”这一计划运行。这个实现使用了Calendrical Calculations Software Package,用于计算当地(给定经度和纬度)的日落时间。

实时保证

在编写使用计划的应用程序时,一定要了解框架在时间方面有什么保证。我的任务是提前还

是延迟执行?如果有提前或者延迟,偏差最大值是多少?不幸的是,对这些问题没有简单的答案。不过在实际中,它的行为对于很多应用程序已经足够了。下面的讨论假设系统时钟是正确的。

因为Scheduler 将计划委托给Timer 类,Scheduler 可以做出的实时保证与Timer 的一样。Timer 用Object.wait(long) 方法计划任务。当前线程要等待直到唤醒它,唤醒可能出于以下原因之一:

1.另一个线程调用对象的notify() 或者notifyAll() 方法。

2.线程被另一个线程中断。

3.在没有通知的情况下,线程被唤醒(称为spurious wakeup,Joshua Bloch 的Effective Java Programming Language Guide 一书中Item 50 对其进行了描述。

4.规定的时间已到。

对于Timer 类来说,第一种可能性是不会发生的,因为对其调用wait() 的对象是私有的。即便如此,Timer 实现仍然针对前三种提前唤醒的原因进行了保护,这样保证了线程在规定时间后才唤醒。目前,Object.wait(long) 的文档注释声明,它会在规定的时间“前后”苏醒,所以线程有可能提前唤醒。在本例中,Timer 会让另一个wait() 执行(scheduledExecutionTime - System.currentTimeMillis())毫秒,从而保证任务永远不会提前执行。任务是否会延迟执行呢?会的。延迟执行有两个主要原因:线程计划和垃圾收集。

Java 语言规范故意没有对线程计划做严格的规定。这是因为Java 平台是通用的,并针对于大范围的硬件及其相关的操作系统。虽然大多数JVM 实现都有公平的线程调度程序,但是这一点没有任何保证——当然,各个实现都有不同的为线程分配处理器时间的策略。因此,当Timer 线程在分配的时间后唤醒时,它实际执行其任务的时间取决于JVM 的线程计划策略,以及有多少其他线程竞争处理器时间。因此,要减缓任务的延迟执行,应该将应用程序中可运行的线程数降至最少。为了做到这一点,可以考虑在一个单独的JVM 中运行调度程序。

对于创建大量对象的大型应用程序,JVM 花在垃圾收集(GC)上的时间会非常多。默认情况下,进行GC 时,整个应用程序都必须等待它完成,这可能要有几秒钟甚至更长的时间(Java 应用程序启动器的命令行选项-verbose:gc 将导致向控制台报告每一次GC 事件)。要将这些由GC 引起的暂停(这可能会影响快速任务的执行)降至最少,应该将应用程序创建的对象的数目降至最低。同样,在单独的JVM 中运行计划代码是有帮助的。同时,可以试用几个微调选项以尽可能地减少GC 暂停。例如,增量GC 会尽量将主收集的代价分散到几个小的收集上。当然这会降低GC 的效率,但是这可能是时间计划的一个可接受的代价。

被计划到什么时候?

如果任务本身能监视并记录所有延迟执行的实例,那么对于确定任务是否能按时运行会很有

帮助。SchedulerTask 类似于TimerTask,有一个scheduledExecutionTime() 方法,它返回计划任务最近一次执行的时间。在任务的run() 方法开始时,对表达式System.currentTimeMillis() - scheduledExecutionTime() 进行判断,可以让您确定任务延迟了多久执行(以毫秒为单位)。可以记录这个值,以便生成一个关于延迟执行的分布统计。可以用这个值决定任务应当采取什么动作——例如,如果任务太迟了,那么它可能什么也不做。在遵循上述原则的情况下,如果应用程序需要更严格的时间保证,可参考Java 的实时规范。

结束语

在本文中,我介绍了Java 定时器框架的一个简单增强,它使得灵活的计划策略成为可能。新的框架实质上是更通用的cron ——事实上,将cron 实现为一个ScheduleIterator 接口,用以替换单纯的Java cron,这是非常有用的。虽然没有提供严格的实时保证,但是许多需要计划定期任务的通用Java 应用程序都可以使用这一框架。

参考资料

·下载本文中使用的源代码。

·“Tuning Garbage Collection with the 1.3.1 Java Virtual Machine”是Sun 的一篇非常有用的文章,它给出了关于如何最小化GC 暂停时间的提示。

·要获得developerWorks 中有关GC 的更多信息,请参阅以下文章:

“Java 理论与实践:垃圾收集简史” (2003 年10 月)。

“Mash that trash”(2003 年7 月)。

“Fine-tuning Java garbage collection performance”(2003 年1 月)。

“Sensible sanitation, Part 1”(2002 年8 月)。

“Sensible sanitation, Part 2”(2002 年8 月)。

“Sensible sanitation, Part 3”(2002 年9 月)。

·在“Java 理论与实践:并发在一定程度上使一切变得简单”(developerWorks,2002 年11 月)中,Brian Goetz 讨论了Doug Lea 的util.concurrent 库,这是一个并发实用工具类的宝库。

·Brian Goetz 的另一篇文章“Threading lightly, Part 2: Reducing contention”(developerWorks,2001 年9 月)分析了线程竞用以及如何减少它。

关于作者

Tom White 是Kizoom 的首席Java 开发人员,Kizoom 是一家领先的英国软件公司,提供向移动设备发送个性化旅行信息的服务。客户包括英国的国家火车操作员、伦敦公共交通系统(national train operator),以及英国国家公共汽车公司。自1999 年成立以来,Kizoom 使用了极限编程的所有方法。自1996 年起,Tom 一直全职编写Java 程序,使用了大部分标准和企业Java API,编写了从客户Swing GUI 和图形到后端消息传送系统等各种应用程序。他在剑桥大学获得了一级荣誉学位(first class honours degree)。工作之余,Tom 喜欢逗他的小女儿开心,观看20 世纪30 年代的好莱坞电影。可以通过tom@https://www.doczj.com/doc/af13170019.html, 与Tom 联系。

Tuning Garbage

Collection

with the 1.3.1 Java

Virtual Machine

See also Performance

Docs

Introduction

The Java 2 Platform is increasingly used for large server applications such as web services. These applications demand scalability, and directly benefit from large numbers of threads, processors, sockets and memory. Yet 'big iron' performance has a reputation as an art form, requiring special expertise beyond what is needed for performance on smaller systems. Fortunately, the Java Virtual Machine (JVM)* and Solaris operating environment provide effective implementations of threads, I/O and memory management. This document addresses a common speed bump on the road to scalable high performance: poorly tuned garbage collection (GC).

Amdahl observed that most workloads cannot be perfectly parallelized; some portion is always sequential and does not benefit from parallelism. This is also true for the Java 2 Platform. In particular, JVMs up to and including version 1.3.1 do not have parallel garbage collection, so the impact of GC on a multiprocessor system grows relative to an otherwise parallel application. The graph below models an ideal system that is perfectly scalable with the exception of GC. The top line (red) is an application spending only 1% of the time in GC on a uniprocessor; this translates into more than 20% loss in throughput at 32 processors. At 10%, not considered an outrageous amount of time in GC in uniprocessor applications, more than 75% of throughput is lost when scaling up.

This demonstrates that issues that appear lost in the noise when developing on small systems may become principal bottlenecks when scaling up. The silver lining is that small improvements in such a bottleneck can produce large gains in performance. For a sufficiently large system it becomes well worthwhile to tune garbage collection.

This document is written from the perspective of 1.3.1 JVM on the Solaris (SPARC Platform Edition) operating environment, because that platform provides the most scalable hardware/software Java 2 platform

today. However, the descriptive text applies to other supported platforms, including Linux, Microsoft Windows, and the Solaris (Intel Architecture) operating environment, to the extent that scalable hardware is available. Although command line options are consistent across platforms, some platforms may have different defaults than described here.

Generations

One of Java 2 Platform's great strengths is that it shields the substantial complexity of memory allocation and garbage collection from the developer. However, once GC has become the principal bottleneck, it becomes worth understanding aspects of this hidden implementation. Garbage collectors make assumptions about the way applications use objects, and these are reflected in tunable parameters that can be adjusted for improved performance without sacrificing the power of the abstraction.

An object is garbage when it can no longer be reached from any pointer in the running program. The most straightforward garbage collection algorithms simply iterate over every reachable object; any objects left over are then known to be garbage. This approach takes time proportional to the number of living objects, which is prohibitive for large applications maintaining lots of living data.

The 1.3 JVM incorporates a number of different garbage collection algorithms that are combined using generational collection. While naive garbage collection examines every living object in the heap, generational collection exploits several empirically observed properties of most applications to avoid extra work.

The most important of these properties is infant mortality. The blue area in the diagram below is a typical distribution for the lifetimes of objects. The sharp peak at the left represents objects that can be reclaimed shortly after being allocated. Iterator objects, for example, are often alive for the duration of a single loop.

Some objects do live longer, and so the distribution stretches out to the the right. For instance, there are typically some objects allocated at initialization that live until the process exits. Between these two extremes are objects that live for the duration of some intermediate computation, seen here as the lump to the right of the infant mortality peak. Some applications have very different looking distributions, but a surprisingly large number possess this general shape. Efficient collection is made possible by focusing on the fact that a majority of objects die young.

To do this, memory is managed in generations: memory pools holding objects of different ages. Garbage collection occurs in each generation when it fills up; these collections are represented on the diagram above with vertical bars. Objects are allocated in eden, and because of infant mortality most objects die there. When Eden fills up it causes a minor collection, in which some surviving objects are moved to an older generation. When older generations need to be collected there is a major collection that is often much slower because it involves all living

objects.

The diagram shows a well-tuned system in which most objects die before they survive to the first garbage collection. The longer an object survives, the more collections it will endure and the slower GC becomes. By arranging for most objects to survive less than one collection, garbage collection can be very efficient. This happy situation can be upset by applications with unusual lifetime distributions, or by poorly sized generations that cause collections to be too frequent.

The default garbage collection parameters were designed to be effective for most small applications. They aren't optimal for many server applications. This leads to the central tenet of this document:

Types of collection

Each generation has an associated type of garbage collection that can be configured to make different algorithmic time, space and pause tradeoffs. In 1.3, the JVM implements three very different garbage collectors:

1.Copying (sometimes called scavenge): this collector very efficiently moves objects

between two or more generations. The source generations are left empty, allowing

remaining dead objects to be reclaimed quickly. However, since it requires empty space

to operate, copying requires more footprint. In 1.3.1 copying collection is used for all

minor collections.

2.Mark-compact: this collector allows generations to be collected in place without

reserving extra memory; however, compaction is significantly slower than copying. In

1.3.1 mark-compact is used for major collections.

3.Incremental (sometimes called train): this collector is used only if -Xincgc is passed on

the command line. By careful bookkeeping, incremental GC collects just a portion of the old generation at a time, trying to spread the large pause of a major collection over many minor collections. However, it is even slower than mark-compact when considering

overall throughput.

Since copying is very fast, a tuning goal is to collect as many objects as possible by copying rather than by compaction or incremental collection.

The default arrangement of generations looks something like this.

At initialization, a maximum address space is virtually reserved but not allocated physical memory unless it is needed. The complete address space reserved for object memory can be divided into the young and old generations.

The young generation consists of eden plus two survivor spaces. Objects are initially allocated in eden. One survivor space is empty at any time, and serves as the destination of the next copying collection of any living objects in eden and the other survivor space. Objects are copied between survivor spaces in this way until they age enough to be tenured (copied to the old generation.)

(Other virtual machines, including the production JVM version 1.2 for the Solaris operating environment, used two equally sized spaces for copying rather than one large eden plus two small spaces. This means the options for sizing the young generation are not directly comparable; see the Performance FAQ for an example.)

The old generation is collected in place by mark-compact. One portion called the permanent generation is special because it holds all the reflective data of the JVM itself, such as class and method objects.

Performance considerations

There are two primary measures of garbage collection performance. Throughput is the percentage of total time not spent in garbage collection, considered over long periods of time.

Throughput includes time spent in allocation (but tuning for speed of allocation is generally not needed.) Pauses are the times when an application appears unresponsive because garbage collection is going on.

Users have different requirements of garbage collection. For example, some consider the right metric for a web server to be throughput, since pauses during garbage collection may be tolerable, or simply obscured by network latencies. But for an interactive graphical program, even short pauses may upset the user experience.

Some users are sensitive to other considerations. Footprint is the working set of a process, measured in pages and cache lines. On systems with limited physical memory or many processes, footprint may dictate scalability. Promptness is the time between when an object becomes dead and when the memory becomes available, an important consideration for distributed systems including RMI.

In general, a particular generation sizing chooses a trade-off between these considerations. For example, a very large young generation may maximize throughput, but does so at the expense of footprint and promptness. Pauses can be minimized by using a small young generation and incremental collection, at the expense of throughput.

There is no one right way to size generations; the best choice is determined by the way the application uses memory as well as user requirements. For this reason the JVM's default GC choices may not be optimal, and may be overridden by the user in the form of command line options below.

Measurement

Throughput and footprint are best measured using metrics particular to the application. For example, throughput of a web server may be tested using a client load generator, while footprint of the server might be measured on the Solaris operating environment using the pmap command. On the other hand, pauses due to GC are easily estimated by inspecting the diagnostic output of the JVM itself.

The command line argument -verbose:gc prints information at every collection. For example, here is output from a large server application:

[GC 325407K->83000K(776768K), 0.2300771 secs]

[GC 325816K->83372K(776768K), 0.2454258 secs]

[Full GC 267628K->83769K(776768K), 1.8479984 secs]

Here we see two minor collections and one major one. The numbers before and after the arrow indicate the combined size of live objects before and after the GC. (After minor collections the count includes objects that aren't necessarily alive but can't be reclaimed, either because they are directly alive, or because they are within or referenced from the old generation.) The

number in parenthesis is the total available space, which is the total heap minus one of the survivor spaces.

Sizing the generations

A number of parameters affect generation size. This diagram illustrates the ones most important to tuning the 1.3.1 JVM. Many parameters are actually ratios x:y, and these are depicted with black (representing x) and grey (representing y) size bars:

Total heap

Since collections occur when generations fill up, throughput is inversely proprotional to the amount of memory available. Total available memory is the most important knob affecting GC performance.

By default, the JVM grows or shrinks the heap at each collection to try to keep the proportion of free space to living objects at each collection within a specific range. This target range is set as a percentage by the parameters -XX:MinHeapFreeRatio= and -XX:MaxHeapFreeRatio=, and the total size is bounded below by -Xms and above by -Xmx . The default parameters for the Solaris (SPARC Platform Edition) operating environment are shown in this table:

Java程序设计在线作业-单选题2

Java程序设计在线作业2 一、单选题(共 10 道试题,共 30 分。) 1. 下列程序的输出结果是import java.io.*; public class abc { public static void main(String args[]) { String s1="Hello!"; String s2=new String("World!"); System.out.println(s1.concat(s2)); } } A. false B. Hello! C. Hello!Wofld! D. 12 2. 在浏览器中执行applet 程序,以下选项中的哪个方法将被最先执行()。 A. init() B. start() C. destroy() D. stop() 3. Java语言的类型是() A. 面向对象语言 B. 面向过程语言 C. 汇编程序 D. 形式语言 4. 下列哪一项不属于Awt布局管理器?() A. GridLayout B. CardLayout C. BorderLayout D. BoxLayout

5. 下面代码的执行结果是什么?( )<% x=3; %><% int x=5; %><%! int x=7; %> x = <%=x%>, <%=this.x%> A. x = 3, 5 B. x = 3, 7 C. x = 5, 3 D. x = 5, 7 6. Java Applet 源程序文件的扩展名为()。 A. .java B. .class C. .html D. .exe 7. 在Java Applet程序用户自定义的Applet子类中,一般需要重载父类的()方法来完成一些画 图操作。() A. start() B. stop() C. init() D. paint() 8. 阅读下面的代码,第10行的语句将调用哪个方法?() 1. class Person { 2. public void printValue(int i, int j) {/*…*/ } 3. public void printV alue(int i){/*...*/ } 4. } 5. public class Teacher extends Person { 6. public void printValue() {/*...*/ } 7. public void printValue(int i) {/*...*/} 8. public static void main(String args[]){ 9. Person t = new Teacher(); 10. t.printValue(10); 11. } 12. } A. 行2 B. 行3 C. 行6

Spring提供的三种定时任务机制及其比较

Spring提供的三种定时任务机制及其比较 定时任务的需求在众多应用系统中广泛存在,在Spring中,我们可以使用三种不同的定时机制,下面一一描述并加以比较 1. 基于Quartz的定时机制

下面详细解释这个类图中涉及的关键类及其使用场景 1.1. SchedulerFactoryBean 这是Spring中基于Quartz的定时机制入口,只要Spring容器装载了这个类,Quartz定时机制就会启动,并加载定义在这个类中的所有trigger Spring配置范例: [xhtml]view plaincopy 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 1.2. CronTriggerBean 实现了Trigger接口,基于Cron表达式的触发器 这种触发器的好处是表达式与linux下的crontab一致,能够满足非常复杂的定时需求,也容易配置

Spring配置范例: [xhtml]view plaincopy 1. 2. 3. 4. 1.3. SimpleTriggerBean 该类也实现了Trigger接口,基于配置的定时调度 这个触发器的优点在于很容易配置一个简单的定时调度策略 Spring配置范例: [xhtml]view plaincopy 1. 2. 3. 4. 5. 6.3600000 7. 8. 9.86400000 10. 11.

Java定时任务ScheduledThreadPoolExecutor

Timer计时器有管理任务延迟执行("如1000ms后执行任务")以及周期性执行("如每500ms执行一次该任务")。但是,Timer存在一些缺陷,因此你应该考虑使用ScheduledThreadPoolExecutor作为代替品,Timer对调度的支持是基于绝对时间,而不是相对时间的,由此任务对系统时钟的改变是敏感的;ScheduledThreadExecutor只支持相对时间。 Timer的另一个问题在于,如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer线程并不捕获异常,所以TimerTask抛出的未检查的异常会终止timer 线程。这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。 例子: packagecom.concurrent.basic; importjava.util.Timer; import java.util.TimerTask; public class TimerTest { private Timer timer = new Timer(); // 启动计时器 public void lanuchTimer() { timer.schedule(new TimerTask() { public void run() { throw new RuntimeException(); } }, 1000 * 3, 500); } // 向计时器添加一个任务 public void addOneTask() { timer.schedule(new TimerTask() { public void run() { System.out.println("hello world"); } }, 1000 * 1, 1000 * 5); }

《java程序设计》作业答案

《JA V A程序设计》作业答案 一、选择题 1、编译HelloWorld.java的正确命令是: C) javac HelloWorld.java 2、正确运行HelloWorld.java的正确命令是: A)java HelloWorld 3、下面程序代码,使用多行注释正确的是: C)/* int k=9; int j=8; k = k + j; */ 4、long型的取值范围是: D)-263~263-1 5、下面不属于Java保留字的是: C)malloc 6、下面属于非法的Java标识符的是: D) abc-d 7、对与System.out.println()语句解释合理的是: C)执行后输出一个空行 8、阅读下面的代码,回答问题, for( m = 0 ; m > -2 ; m -- ){….} For循环执行多少次: C)2 9、阅读下面的代码,回答问题, for( m = 0; m < 5; m++ ) { System.out.print( m + "," ); if( m == 3 ) break; } 执行结果是: C)0,1,2,3, 10、阅读下面的代码,回答问题, public class Ex { int x = 1; void m() { int x = 3; System.out.print( "x= " + x); } public static void main( String[] args ) { Ex ex = new Ex();

ex.m(); } } 执行结果是: B)x=3 11、下面语句在编译时不会出现错误信息的是: a) float f = 1.3; b) char c = "a"; c) byte b = 257; d) boolean b = null; e) int i = 10; 12、编译和运行下面的代码,会有什么结果产生: public class MyClass { public static void main(String arguments[]) { amethod(arguments); } public void amethod(String[] arguments) { System.out.println(arguments); System.out.println(arguments[1]); } } a) 错误,静态方法不能直接引用非静态方法b) 错误,主方法有错误 c) 错误,数据定义有错误d) 方法amethod必须被声明为String型 13、编译期间会出错的是: a) import java.awt.*; package Mypackage; class Myclass {} b) package MyPackage; import java.awt.*; class MyClass{} c) /*This is a comment */ package MyPackage; import java.awt.*; class MyClass{} 14、byte型的变量的表示范围为: a) -128 to 127 b) (-2 power 8 )-1 to 2 power 8 c) -255 to 256 d) 依赖Java虚拟机而定 15、在命令行运行命令:java myprog good morning 会有什么结果显示出来: public class myprog{ public static void main(String argv[]) { System.out.println(argv[2]) } } a) myprog b) good c) morning

Quartz+spring定时器实例用

Spring+Quartz定时器例子如下: 1. javabean类 在Test.QuartzJob中 1.package Test; 2. 3.public class QuartzJob { 4.public void work() 5. { 6. System.out.println("Quartz的任务调度!!!"); 7. } 8. } 1. 2. 7. 8. 9. 10. 11. 13. 14. 15. 16. 17. 18. 19.work 20. 21. 22. 23. 25. 26.

Java程序设计课程作业

Java程序设计课程作业 第一章绪论 1、安装Java SDK到你的电脑中。 2、选择安装一种Java开发工具到你的电脑中。Jcreater、NetBeans、Eclipse 3、编译并运行一个“Hello World”Java程序。 程序代码: // public class App2_1 { public static void main(String[]args) { System.out.println("hello Word"); } } 4、编译并运行一个Java Applet程序。 答:编译成功,不过浏览器不显示自己的Applet程序,还在学习中,错误的原因是自己电脑上java的安全设置的原因,修改后运行成功。 第二章Java语法基础 1、下列表达式是否有错?若有错,请说明何处出现何种错误;若无错,请给出其值。 (1) 3+4<<2^-8 没有错误,运行结果为-28 (2) 36>>2*4&48<<8/4+2 运行结果为0

有错误,||这个运算规律是两边均为boolean型 (4) 2*4&&0<2||4%2 有错误,||这个运算规律是两边均为boolean型 2、任意准备一份学生成绩表,其中包括至少3门课程、每门课程至少10名同学的成绩。请编写程序完成以下功能:(1) 统计并输出各门课程的平均成绩。(2) 输出等级表:优、良、中、及格及不及格。 import java.util.*; class student{ String num; doublemath; doubleenglish; doublechinese; } publicclass Test{ publicstaticvoid main(String[]agrs){ student stu[]=new student[11]; for(int i=0;i<10;i++) stu[i]=new student(); Scanner reader=new Scanner(System.in); System.out.println("请依次输入十个同学的数学,英语。语文的成绩:"); for(int i=0;i<=10;i++){ System.out.println("第"+(i+1)+"同学的数学,英语。语文的成绩:"); stu[i].math=reader.nextInt(); stu[i].english=reader.nextInt(); stu[i].chinese=reader.nextInt(); } double sum=0; for(int i=0;i<10;i++) sum=sum+stu[i].math; float A=(float)sum/10; System.out.println("数学平均成绩:"+A); //int sum;

Java每天定时执行任务

Java每天定时执行任务 java定时任务,每天定时执行任务。以下是这个例子的全部代码。 public class TimerManager { //时间间隔 private static final long PERIOD_DAY = 24 * 60 * 60 * 1000; public TimerManager() { Calendar calendar = Calendar.getInstance(); /*** 定制每日2:00执行方法***/ calendar.set(Calendar.HOUR_OF_DAY, 2); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); Date date=calendar.getTime(); //第一次执行定时任务的时间 //如果第一次执行定时任务的时间小于当前的时间 //此时要在第一次执行定时任务的时间加一天,以便此任务在下个时间点执行。如果不加一天,任务会立即执行。 if (date.before(new Date())) { date = this.addDay(date, 1); } Timer timer = new Timer(); NFDFlightDataTimerT ask task = new NFDFlightDataTimerTask(); //安排指定的任务在指定的时间开始进行重复的固定延迟执行。 timer.schedule(task,date,PERIOD_DAY); } // 增加或减少天数 public Date addDay(Date date, int num) { Calendar startDT = Calendar.getInstance(); startDT.setTime(date); startDT.add(Calendar.DAY_OF_MONTH, num); return startDT.getTime(); }

Java程序设计大作业实验报告

目录 一、前言 (2) 二、需求分析 (3) 三、系统总体设计 (3) 3.1系统总体设计系统思路 (3) 3.2数据库设计 (4) 3.2.1 login1表的设计和数据 (4) 3.2.2 student表的设计和数据 (5) 3.2.3 course表的设计和数据 (5) 3.2.4 score表的设计和数据 (5) 3.3系统功能模块设计 (6) 四、系统详细设计 (7) 4.1登录模块 (7) 4.2 学生模块 (7) 4.3 教师模块 (7) 4.4 管理员模块 (8) 五、系统测试及运行结果 (9) 5.1 主界面 (9) 5.2 学生管理中心界面 (9) 5.3 教师管理中心界面 (10) 5.4 管理员管理中心界面 (10)

5.5 查询课表界面 (11) 5.6 查询成绩界面 (11) 5.7 查询教学情况界面 (11) 5.8 查询所有学生成绩界面 (12) 5.9 学生信息管理界面 (12) 5.10 学生成绩管理界面 (13) 5.11 用户管理界面 (13) 六、实验总结 (14) 七、参考文献 (14) 一、前言 随着计算机在人们生活中的普及和网络时代的来临,对信息的要求日益增加,学生信息管理业务受到了较为强烈的冲击,传统的手工管理方式传统的手工管理方式已不能适应现在的信息化社会。如何利用现有的先进计算机技术来解决学生信息管理成为当下的一个重要问题,学生信息管理系统是典型的信息管理系统,其开发主要就是针对前台的页面展示以及后台数据的管理。对于前者,要求应用程序功

能完备,易于使用,界面简单;而对于后者,则要求数据库具有一致性、完整性,并能够依据前台的操作来对应操作后台数据库达到一定的安全性。 本学生信息管理系统主要采用的纯JAVA代码实现图形界面系统的开发,以及数据库知识进行数据的查询,删除,插入和更新。本系统主要分为三个部分:学生模块、教师模块、管理员模块。其中学生模块实现的功能:查询课表信息和查询成绩。教师模块实现的功能:查询课表信息、查询教学情况和查询所有学生的各科成绩。管理员模块实现的功能:课表信息的管理、学生信息管理、学生成绩管理和用户信息管理。 二、需求分析 用JAVA语言实现学生信息管理系统的图形界面的编程。主要实现以下几个重要功能: ①实现三种不同身份(学生、教师、管理员)登录学生信息管理系统。(其中的数据信息保存在数据库中)

springquartz实现定时任务的配置方法

Spring+Quartz实现定时任务的配置方法 第一步:.导入相关的jar包 (1)spring.jar (2)quartz-1.6.0.jar (3)相关包 commons-collections-3.2.jar ; commons-logging-1.1.1.jar; log4j-1.2.16.jar 第二步:创建一个类来定义工作 定义Quartz工作的第一步是创建一个类来定义工作。要做到这一点,你需要从Spring 的QuartzJobBean中派生子类。 第三步:配置JobDetail

值得注意的是,在这里你并没有直接声明一个TopTenTask Bean,而是声明了一个JobDetailBean。这是使用Quartz时的一个特点。 JobDetailBean是Quartz的org.quartz.JobDetail的子类,它要求通过jobClass属性来设置一个Job对象。 使用Quartz的JobDetail中的另一个特别之处是TopTenTask的timeout属性是间接设置的。JobDetail的jobDataAsMap属性接受一个java.util.Map,其中包含了需要设置给jobClass的各种属性。 在这里,这个map包含了一个键值为timeout。当JobDetailBean实例化时,它会将5注入到EmailReportJob的timeout属性中。 第四步:配置Trigger 工作已经被定义好了,接下来你需要调度这个工作。 Quartz的org.quartz.Trigger类描述了何时及以怎样的频度运行一个Quartz工作。 Spring提供了两个触发器,SimpleTriggerBean和CronTriggerBean。 SimpleTriggerBean与ScheduledTimerTask类似。你可以用它来指定一个工作应该以怎样的频度运行,以及(可选地)在第一次运行工作之前应该等待多久。 例如,要调度报表工作每24小时运行一次,第一次在1小时之后开始运行,可以按照以下方式进行声明: 3600000 86400000 属性jobDetail装配了将要被调度的工作,在这个例子中是topTenTask Bean。属性repeatInterval告诉触发器以怎样的频度运行这个工作(以毫秒作为单位)。这里,我们

java语言程序设计作业答案

Java语言程序设计(郑莉) 第二章习题答案 1.什么是对象、类,它们之间的联系? 答:1)对象是包含现实世界物体特征的抽象实体,它反映系统为之保存信息和与它交互的能力。对象是一些属性及服务的封装体,在程序设计领域,可以用“对象=数据+作用于这些数据上的操作”来表示。现实生活中对象是指客观世界的实体;在程序中对象是指一组变量和相关方法的集合。 2)类是既有相同操作功能和相同的数据格式的对象的集合与抽象! 3)两者的关系:对象是类的具体实例.。 4.请解释类属性、实例属性及其区别。 答:实例属性,由一个个的实例用来存储所有实例都需要的属性信息,不同实例的属性值可能会不同。 5.请解释类方法、实例属性及其区别。 答:实例方法表示特定对象的行为,在声明时前面不加static修饰符,在使用时需要发送给一个类实例。 类方法也称为静态方法,在方法声明时前面需加static修饰符,类方法表示具体实例中类对象的共有行为。 区别:实例方法可以直接访问实例变量,调用实例方法,实例方法可以直接访问类变量,调用类方法;类方法可以直接调用类变量和类方法,类方法不能直接调用实例变量和实例方法; 6.类的访问控制符有哪几种?具体含义及其区别。 答:类的访问控制符只有public(公共类)及无修饰符(默认类)两种。 区别:当使用public修饰符时表示所有其他的类都可以使用此类;当没有修饰符时,则只有与此类处于同一包中的其他类可以使用类。 7类成员的访问控制符有哪几种?他们对类成员分别有哪些访问限制的作用? 答: 类成员的访问控制符有public,private,protecte及无修饰符. public(公有的):用public修饰的成分表示公有的,也就是它可以被其他任何对象访问(前提是对累成员所在的类访问有访问权限). P rivate(保护的):类中限定为private的成员只能被这个类本身访问,在类外不可见。proteced(保护的)用该关键字修饰的成分是受保护的,只可以被同一类及其子类的实例对象访问。 无修饰符(默认的):public,private,protected这个三个限定符不是必须写的。如果不写,则表明是“friendly”,相应的成分可以被所在保重的各类访问。 8简述构造方法的特点? 答: 构造方法主要有以下特点: (1)构造方法的方法名与类名相同; (2)构造方法没有返回类型(修饰符void也不能有); (3)构造方法通常被声明为公有的(public);

java定时任务

Java定时任务的实现 一、通过java本身提供的接口实现 关键词:监听器(Listener)和定时器(Timer)任务(Task)。 方式: 首先:建立一个监听器 MyListener import java.util.Timer; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyListener implements ServletContextListener { private Timer timer = null; public void contextInitialized(ServletContextEvent event) { timer = new Timer(true); //设置任务计划,启动和间隔时间 timer.schedule(new MyTask(), 0, 86400000); } public void contextDestroyed(ServletContextEvent event) { timer.cancel(); } } 监听器web.xml配置 com.fastunit.samples.listener.MyListener 任务MyTask import java.util.TimerTask; public class MyTask extends TimerTask { // 继承TimerTask public void run() { // 此处添加具体需要执行的任务代码 } } 上面的代码虽然简单实用,但是在web项目中的时候为了避免无法加载到的问题,在web

Azkaban-开源任务调度程序(使用篇)

登录 https://localhost:8443 注意是https,采用的是jetty ssl链接。输入账号密码azkaban/azkanban(如果你之前没有更改的话) 首页 首页有四个菜单 ?projects:最重要的部分,创建一个工程,所有flows将在工程中运行。 ?scheduling:显示定时任务 ?executing:显示当前运行的任务 ?history:显示历史运行任务 主要介绍projects部分 首先创建一个工程,填写名称和描述,比如o2olog。 o2olog工程 Flows:工作流程,有多个job组成 Permissions:权限管理 Project Logs:工程日志 创建工程: 创建之前我们先了解下之间的关系,一个工程包含一个或多个flows,一个flow包含多个job。job是你想在azkaban中运行的一个进程,可以是简单的linux命令,可是java程序,也可以是复杂的shell脚本,当

然,如果你安装相关插件,也可以运行插件。一个job可以依赖于另一个job,这种多个job和它们的依赖组成的图表叫做flow。 job创建 创建job很简单,只要创建一个以.job结尾的文本文件就行了,例如我们创建一个工作,用来将日志数据导入hive中(关于大数据方面的东西,不在重复,可以理解为,将日志所需数据导入的mysql中),我们创建o2o_2_hive.job type=command command=echo "data 2 hive" 一个简单的job就创建好了,解释下,type的command,告诉azkaban用unix原生命令去运行,比如原生命令或者shell脚本,当然也有其他类型,后面说。 一个工程不可能只有一个job,我们现在创建多个依赖job,这也是采用azkaban的首要目的。 flows创建 我们说过多个jobs和它们的依赖组成flow。怎么创建依赖,只要指定dependencies参数就行了。比如导入hive前,需要进行数据清洗,数据清洗前需要上传,上传之前需要从ftp获取日志。 定义5个job: 1.o2o_2_hive.job:将清洗完的数据入hive库 2.o2o_clean_data.job:调用mr清洗hdfs数据 3.o2o_up_2_hdfs.job:将文件上传至hdfs 4.o2o_get_file_ftp1.job:从ftp1获取日志 5.o2o_get_file_fip2.job:从ftp2获取日志 依赖关系: 3依赖4和5,2依赖3,1依赖2,4和5没有依赖关系。 o2o_2_hive.job type=command # 执行sh脚本,建议这样做,后期只需维护脚本就行了,azkaban定义工作流程command=sh /job/o2o_2_hive.sh dependencies=o2o_clean_data o2o_clean_data.job type=command # 执行sh脚本,建议这样做,后期只需维护脚本就行了,azkaban定义工作流程command=sh /job/o2o_clean_data.sh dependencies=o2o_up_2_hdfs o2o_up_2_hdfs.job

Java程序设计作业

要求:一个院系一个年级的同学题目不能相同,所以选择题目时应避免做相同的题目,其它学院和年级的同学相对自由一点。从22 道题目中任选一道,按实验指导书模式那样完成即可,写好大作业报告,同时写上自己的姓名、学号、学院和年级 1、编写一个Java 应用程序,从键盘读取用户输入两个字符串,并重载3 个函数 分别实现这两个字符串的拼接、整数相加和浮点数相加。要进行异常处理,对输入的不符合要求的字符串提示给用户,不能使程序崩溃。 2、有工人,农民,教师,科学家,服务生,其中,工人,农民,服务生只有基本工资. 教师除基本工资外,还有课酬(元/天),科学家除基本工资外,还有年终奖,请你写 出相关类,将各种类型的员工的全年工资打印出来; 3、创建一个复数类complex,对复数进行数学运算,复数具有如下格式:RealPart+ImaginaryPart*I 其中,I 为-1的平方根。 要求如下: (1)利用浮点变量表示此类的私有数据。提供两个构造方法,一个用于此类声明时对象的初始化;一个为带默认值得无参构造方法。 (2)提供两复数加、减、乘的运算方法。 (3)按格式(a,b)打印复数。其中a 为实部,b 为虚部。 4、(1)编写一个圆类Circle,该类拥有:①一个成员变量 Radius(私有,浮点型);// 存放圆的半径; ②两个构造方法 Circle( ) // 将半径设为0 Circle(double r ) //创建Circle对象时将半径初始化为 r ③三个成员方法 double getArea( ) //获取圆的面积 double getPerimeter( ) //获取圆的周长 void show( ) //将圆的半径、周长、面积输出到屏幕 (2)编写一个圆柱体类Cylinder,它继承于上面的Circle 类。还拥有: ①一个成员变量 double hight(私有,浮点型);// 圆柱体的高; ②构造方法 Cylinder (double r, double h ) //创建Circle 对象时将半径 初始化为r ③成员方法 double getVolume( ) //获取圆柱体的体积 void showVolume( ) //将圆柱体的体积输出到屏幕 编写应用程序,创建类的对象,分别设置圆的半径、圆柱体的高,计算并分别显示圆半径、圆面积、圆周长,圆柱体的体积。

java定时器

util包中的定时器学习相对比较简单,学习java定时器主要要熟悉两个类,Timer类和TimerTask类。 定时器类Timer在java.util包中。使用时,先实例化,然后使用实例的schedule(TimerTask task, long delay)方法,设定指定的任务task在指定的延迟delay后执行。定时器任务类TimerTask 是抽象类,继承并重写其run()方法,可实现具体任务。 schedule(TimerTask task, Date time)设定指定任务task在指定时间time执行。 cancel()方法结束这个定时器。 schedule(TimerTask task, long delay, long period)方法设定指定任务task在指定延迟delay后进行固定延迟peroid的执行。 scheduleAtFixedRate(TimerTask task, long delay, long period)方法设定指定任务task在指定延迟delay后进行固定频率peroid的执行。 要实现一个定时任务,运用java中的Timer和TimerTask类可以非常容易实现实时调用处理函数。这两个类使用起来非常方便,可以完成我们对定时器的绝大多数需要。 package com.csdn.heima; import java.io.IOException; import java.util.Scanner; import java.util.Timer; public class TimerTest { public static void main(String[] args){ Timer timer = new Timer(); timer.schedule(new MyTask(), 1000, 3000);//在1秒后执行此任务,以后每隔1秒执行这个MyTask任务. while(true){ Scanner scan = new Scanner(System.in); String str = scan.nextLine(); if(str.equals("ok")){ timer.cancel();// 终止此计时器,丢弃所有当前已安排的任务。 } } } static class MyTask extends java.util.TimerTask{

Java程序设计作业答案

1、创建一个Java程序,输出自己的基本信息:名字、学号以及本学期所修课程名称。答: package com.study; public class Example{ public static void main(String[] args) { System.out.println("名字"+"朱朝龙"); System.out.println("学号"+"1234567"); System.out.println("修课程名称"+"Java程序设计"); } } 2、叙述标识符的定义。指出下列用户自定义的标识符中哪些是合法的,那些是非法的?为什么? 2、abc AbC _2xy x$y if$ Else do b(3) ‘def’ Chine_bb 3by AbsFloat 答: 标识符:是用户编程时使用的名字 1.标识符由字母、数字、下划线“_”、美元符号“$”组成,并且首字母 不能是数字。 2.不能把java关键字和作为标识符。 3.标识符没有长度限制。 4.标识符对大小写敏感。 合法标识符为:abc AbC _2xy x$y if$ Else Chine_bb AbsFloat 非法表示符为:do (关键字);b(3) ‘def’(包含非字母、数字、下划线“$”字符);3by(数字开头) 3、设有变量说明语句: int a = 15; boolean b,e; char c, d; float x = 9.2f, y, z; 求出下列表达式的值: (1) b = 5>4||x>25; 答:true (2) e = !(a > x); 答:false (3) c = ‘a’ + 5; 答:f (4)y = x + a % 3 + x/2;

Java里timer执行定时任务

java定时任务Timer 关于定时任务,似乎跟时间操作的联系并不是很大,但是前面既然提到了定时任务,索性在这里一起解决了。设置定时任务很简单,用Timer类就搞定了。 一、延时执行首先,我们定义一个类,给它取个名字叫TimeTask,我们的定时任务,就在这个类的main函数里执行。代码如下: 解释一下上面的代码。上面的代码实现了这样一个功能,当TimeTask程序启动以后,过一分钟后执行某项任务。很简单吧:先new一个Timer对象,然后调用它的schedule方法,这个方法有四个重载的方法,这里我们用其中一个, 首先,第一个参数第一个参数就是我们要执行的任务。这是一个TimerTask对象,确切点说是一个实现TimerTask的类的对象,因为TimerTask是个抽象类。上面的代码里面,Task就是我们自己定义的实现了TimerTask的类,因为是在同一个包里面,所以没有显性的import进来。Task类的代码如下 我们的Task必须实现TimerTask的方法run,要执行的任务就在这个run方法里面,这里,我们只让它往控制台打一行字。第二个参数第二个参数是一个long型的值。这是延迟的时间,就是从程序开始以后,再过多少时间来执行定时任务。这个long型的值是毫秒数,所以前面我们的程序里面,过一分钟后执行用的参数值就是60 * 1000。 二、循环执行设置定时任务的时候,往往我们需要重复的执行这样任务,每隔一段时间执行一次,而上面的方法是只执行一次的,这样就用到了schedule方法的是另一个重载函数

前两个参数就不用说什么了,最后一个参数就是间隔的时间,又是个long型的毫秒数(看来java里涉及到时间的,跟这个long是脱不了干系了),比如我们希望上面的任务从第一次执行后,每个一分钟执行一次,第三个参数值赋60 * 1000就ok了。 三、指定执行时间既然号称是定时任务,我们肯定希望由我们来指定任务指定的时间,显然上面的方法就不中用了,因为我们不知道程序什么时间开始运行,就没办法确定需要延时多少。没关系,schedule 四个重载的方法还没用完呢。用下面这个就OK了: 比如,我们希望定时任务2006年7月2日0时0分执行,只要给第二个参数传一个时间设置为2006年7月2日0时0分的Date对象就可以了。有一种情况是,可能我们的程序启动的时候,已经是2006 年7月3日了,这样的话,程序一启动,定时任务就开始执行了。schedule最后一个重载的方法是 没必要说什么了吧:) 四、j2ee中的定时任务在实际的项目中,往往定时任务需要对web工程中的资源进行操作,这样一来,用上面的单个程序的方式可能就有点力不从心了,因为很多web工程的资源它操作不到。解决的办法是,使用Servlet,把执行定时任务的那些代码放到Servlet的init()函数里就可以了,这个easy,就没有必要再写示例代码了吧。

JAVA程序设计作业题

JA V A程序设计作业题 1. 编写程序实现单链表,要提供插入,删除,排序,统计等功能,链表节点中的数据要求 是整数。 2. 定义直线类,并提供判断两条直线是否相交等功能。 3. 编写程序实现将BASE64编码和解码功能,将UNICODE字符串“中国”编码为BASE64格式的数据,并解码。 4. 打印所有3位的水仙花数,水仙花数是指其各位数字的立方和等于其自身,例如 153=1*1*1 + 5*5*5 + 3*3*3 5. 随机产生7个1至35之间(包括1和35)的不重复整数,并排序输出。 6. 输出某个整数数组的最大值和最小值。 7. 11/17的小数点后第1000位是几? 8. 判断某字符串内容是否是合法的EMAIL地址。条件为必须包含唯一一个@字符,该字符 不是首字符也不是尾字符。 9. 求fibonacci数列第100项的值。fibonacci数列的第一项的值为1,第二项的值也为1,第 三项以后的值为其前两项的和。要求使用循环和递归的方法来实现。 10. 编写程序实现文件服务功能。 运行命令: java FTServer java FTClient host put adir|afile java FTClient host get 例如: java FTClient 192.168.0.5 put a.txt 该命令实现将当前文件夹下面的a.txt文件上传到 192.168.0.5服务器的共享文件夹下。 java FTClient 192.168.0.5 put c:\test\b.pdf 该命令实现将c:\test\b.pdf文件上传到 192.168.0.5服务器的共享文件夹下。 java FTClient 192.168.0.5 put c:\test 运行该命令,在控制台输出该文件夹下的 子文件(不包括子目录下的子文件),假定, 在c:\test文件夹下有文件a1.doc,a2.doc, b1.pdf,b2.pdf,以及子文件夹abc 那么运行上面的命令,程序输出: java FTClient 192.168.0.5 put c:\test 1: a1.doc 2: a2.doc 3: b1.pdf 4: b2.pdf please input your choice:

相关主题
文本预览
相关文档 最新文档