<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    新的起點(diǎn) 新的開始

    快樂生活 !

    轉(zhuǎn):JAVA計劃任務(wù) (先保留下來慢慢看)

    所 有類型的 Java 應(yīng)用程序一般都需要計劃重復(fù)執(zhí)行的任務(wù)。企業(yè)應(yīng)用程序需要計劃每日的日志或者晚間批處理過程。一個 J2SE 或者 J2ME 日歷應(yīng)用程序需要根據(jù)用戶的約定計劃鬧鈴時間。不過,標(biāo)準(zhǔn)的調(diào)度類 Timer 和 TimerTask 沒有足夠的靈活性,無法支持通常需要的計劃任務(wù)類型。在本文中,Java 開發(fā)人員 Tom White 向您展示了如何構(gòu)建一個簡單通用的計劃框架,以用于執(zhí)行任意復(fù)雜的計劃任務(wù)。

    我將把 java.util.Timer 和 java.util.TimerTask 統(tǒng)稱為 Java 計時器框架,它們使程序員可以很容易地計劃簡單的任務(wù)(注意這些類也可用于 J2ME 中)。在 Java 2 SDK, Standard Edition, Version 1.3 中引入這個框架之前,開發(fā)人員必須編寫自己的調(diào)度程序,這需要花費(fèi)很大精力來處理線程和復(fù)雜的 Object.wait() 方法。不過,Java 計時器框架沒有足夠的能力來滿足許多應(yīng)用程序的計劃要求。甚至一項需要在每天同一時間重復(fù)執(zhí)行的任務(wù),也不能直接使用 Timer 來計劃,因為在夏令時開始和結(jié)束時會出現(xiàn)時間跳躍。

    本文展示了一個通用的 Timer 和 TimerTask 計劃框架,從而允許更靈活的計劃任務(wù)。這個框架非常簡單 —— 它包括兩個類和一個接口 —— 并且容易掌握。如果您習(xí)慣于使用 Java 定時器框架,那么您應(yīng)該可以很快地掌握這個計劃框架。

    計劃單次任務(wù)

    計劃框架建立在 Java 定時器框架類的基礎(chǔ)之上。因此,在解釋如何使用計劃框架以及如何實(shí)現(xiàn)它之前,我們將首先看看如何用這些類進(jìn)行計劃。

    想像一個煮蛋計時器,在數(shù)分鐘之后(這時蛋煮好了)它會發(fā)出聲音提醒您。清單 1 中的代碼構(gòu)成了一個簡單的煮蛋計時器的基本結(jié)構(gòu),它用 Java 語言編寫:

    清單 1. EggTimer 類

    package org.tiling.scheduling.examples;

    import java.util.Timer;
    import java.util.TimerTask;

    public class EggTimer {
    private final Timer timer = new Timer();
    private final int minutes;

    public EggTimer(int minutes) {
    this.minutes = minutes;
    }

    public void start() {
    timer.schedule(new TimerTask() {
    public void run() {
    playSound();
    timer.cancel();
    }
    private void playSound() {
    System.out.println("Your egg is ready!");
    // Start a new thread to play a sound...
    }
    }, minutes * 60 * 1000);
    }

    public static void main(String[] args) {
    EggTimer eggTimer = new EggTimer(2);
    eggTimer.start();
    }

    }


    EggTimer 實(shí)例擁有一個 Timer 實(shí)例,用于提供必要的計劃。用 start() 方法啟動煮蛋計時器后,它就計劃了一個 TimerTask,在指定的分鐘數(shù)之后執(zhí)行。時間到了,Timer 就在后臺調(diào)用 TimerTask 的 start() 方法,這會使它發(fā)出聲音。在取消計時器后這個應(yīng)用程序就會中止。

    計劃重復(fù)執(zhí)行的任務(wù)

    通過指定一個固 定的執(zhí)行頻率或者固定的執(zhí)行時間間隔,Timer 可以對重復(fù)執(zhí)行的任務(wù)進(jìn)行計劃。不過,有許多應(yīng)用程序要求更復(fù)雜的計劃。例如,每天清晨在同一時間發(fā)出叫醒鈴聲的鬧鐘不能簡單地使用固定的計劃頻率 86400000 毫秒(24 小時),因為在鐘撥快或者撥慢(如果您的時區(qū)使用夏令時)的那些天里,叫醒可能過晚或者過早。解決方案是使用日歷算法計算每日事件下一次計劃發(fā)生的時間。 而這正是計劃框架所支持的。考慮清單 2 中的 AlarmClock 實(shí)現(xiàn):

    清單 2. AlarmClock 類

    package org.tiling.scheduling.examples;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import org.tiling.scheduling.Scheduler;
    import org.tiling.scheduling.SchedulerTask;
    import org.tiling.scheduling.examples.iterators.DailyIterator;

    public class AlarmClock {

    private final Scheduler scheduler = new Scheduler();
    private final SimpleDateFormat dateFormat =
    new SimpleDateFormat("dd MMM yyyy HH:mm:ss.SSS");
    private final int hourOfDay, minute, second;

    public AlarmClock(int hourOfDay, int minute, int second) {
    this.hourOfDay = hourOfDay;
    this.minute = minute;
    this.second = second;
    }

    public void start() {
    scheduler.schedule(new SchedulerTask() {
    public void run() {
    soundAlarm();
    }
    private void soundAlarm() {
    System.out.println("Wake up! " +
    "It&quots " + dateFormat.format(new Date()));
    // Start a new thread to sound an alarm...
    }
    }, new DailyIterator(hourOfDay, minute, second));
    }

    public static void main(String[] args) {
    AlarmClock alarmClock = new AlarmClock(7, 0, 0);
    alarmClock.start();
    }
    }


    注 意這段代碼與煮蛋計時器應(yīng)用程序非常相似。AlarmClock 實(shí)例擁有一個 Scheduler (而不是 Timer)實(shí)例,用于提供必要的計劃。啟動后,這個鬧鐘對 SchedulerTask (而不是 TimerTask)進(jìn)行調(diào)度用以發(fā)出報警聲。這個鬧鐘不是計劃一個任務(wù)在固定的延遲時間后執(zhí)行,而是用 DailyIterator 類描述其計劃。在這里,它只是計劃任務(wù)在每天上午 7:00 執(zhí)行。下面是一個正常運(yùn)行情況下的輸出:

    Wake up! It&quots 24 Aug 2003 07:00:00.023
    Wake up! It&quots 25 Aug 2003 07:00:00.001
    Wake up! It&quots 26 Aug 2003 07:00:00.058
    Wake up! It&quots 27 Aug 2003 07:00:00.015
    Wake up! It&quots 28 Aug 2003 07:00:00.002
    ...


    DailyIterator 實(shí)現(xiàn)了 ScheduleIterator,這是一個將 SchedulerTask 的計劃執(zhí)行時間指定為一系列 java.util.Date 對象的接口。然后 next() 方法按時間先后順序迭代 Date 對象。返回值 null 會使任務(wù)取消(即它再也不會運(yùn)行)—— 這樣的話,試圖再次計劃將會拋出一個異常。清單 3 包含 ScheduleIterator 接口:

    清單 3. ScheduleIterator 接口

    package org.tiling.scheduling;

    import java.util.Date;

    public interface ScheduleIterator {
    public Date next();
    }


    DailyIterator 的 next() 方法返回表示每天同一時間(上午 7:00)的 Date 對象,如清單 4 所示。所以,如果對新構(gòu)建的 next() 類調(diào)用 next(),那么將會得到傳遞給構(gòu)造函數(shù)的那個日期當(dāng)天或者后面一天的 7:00 AM。再次調(diào)用 next() 會返回后一天的 7:00 AM,如此重復(fù)。為了實(shí)現(xiàn)這種行為,DailyIterator 使用了 java.util.Calendar 實(shí)例。構(gòu)造函數(shù)會在日歷中加上一天,對日歷的這種設(shè)置使得第一次調(diào)用 next() 會返回正確的 Date。注意代碼沒有明確地提到夏令時修正,因為 Calendar 實(shí)現(xiàn)(在本例中是 GregorianCalendar)負(fù)責(zé)對此進(jìn)行處理,所以不需要這樣做。

    清單 4. DailyIterator 類

    package org.tiling.scheduling.examples.iterators;

    import org.tiling.scheduling.ScheduleIterator;

    import java.util.Calendar;
    import java.util.Date;

    /**
    * A DailyIterator class returns a sequence of dates on subsequent days
    * representing the same time each day.
    */
    public class DailyIterator implements ScheduleIterator {
    private final int hourOfDay, minute, second;
    private final Calendar calendar = Calendar.getInstance();

    public DailyIterator(int hourOfDay, int minute, int second) {
    this(hourOfDay, minute, second, new Date());
    }

    public DailyIterator(int hourOfDay, int minute, int second, Date date) {
    this.hourOfDay = hourOfDay;
    this.minute = minute;
    this.second = second;
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
    calendar.set(Calendar.MINUTE, minute);
    calendar.set(Calendar.SECOND, second);
    calendar.set(Calendar.MILLISECOND, 0);
    if (!calendar.getTime().before(date)) {
    calendar.add(Calendar.DATE, -1);
    }
    }

    public Date next() {
    calendar.add(Calendar.DATE, 1);
    return calendar.getTime();
    }

    }


    實(shí)現(xiàn)計劃框架

    在 上一節(jié),我們學(xué)習(xí)了如何使用計劃框架,并將它與 Java 定時器框架進(jìn)行了比較。下面,我將向您展示如何實(shí)現(xiàn)這個框架。除了 清單 3 中展示的 ScheduleIterator 接口,構(gòu)成這個框架的還有另外兩個類 —— Scheduler 和 SchedulerTask 。這些類實(shí)際上在內(nèi)部使用 Timer 和 SchedulerTask,因為計劃其實(shí)就是一系列的單次定時器。清單 5 和 6 顯示了這兩個類的源代碼:

    清單 5. Scheduler

    package org.tiling.scheduling;

    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;

    public class Scheduler {

    class SchedulerTimerTask extends TimerTask {
    private SchedulerTask schedulerTask;
    private ScheduleIterator iterator;
    public SchedulerTimerTask(SchedulerTask schedulerTask,
    ScheduleIterator iterator) {
    this.schedulerTask = schedulerTask;
    this.iterator = iterator;
    }
    public void run() {
    schedulerTask.run();
    reschedule(schedulerTask, iterator);
    }
    }

    private final Timer timer = new Timer();

    public Scheduler() {
    }

    public void cancel() {
    timer.cancel();
    }

    public void schedule(SchedulerTask schedulerTask,
    ScheduleIterator iterator) {

    Date time = iterator.next();
    if (time == null) {
    schedulerTask.cancel();
    } else {
    synchronized(schedulerTask.lock) {
    if (schedulerTask.state != SchedulerTask.VIRGIN) {
    throw new IllegalStateException("Task already
    scheduled " + "or cancelled");
    }
    schedulerTask.state = SchedulerTask.SCHEDULED;
    schedulerTask.timerTask =
    new SchedulerTimerTask(schedulerTask, iterator);
    timer.schedule(schedulerTask.timerTask, time);
    }
    }
    }

    private void reschedule(SchedulerTask schedulerTask,
    ScheduleIterator iterator) {

    Date time = iterator.next();
    if (time == null) {
    schedulerTask.cancel();
    } else {
    synchronized(schedulerTask.lock) {
    if (schedulerTask.state != SchedulerTask.CANCELLED) {
    schedulerTask.timerTask =
    new SchedulerTimerTask(schedulerTask, iterator);
    timer.schedule(schedulerTask.timerTask, time);
    }
    }
    }
    }

    }


    清單 6 顯示了 SchedulerTask 類的源代碼:

    package org.tiling.scheduling;

    import java.util.TimerTask;

    public abstract class SchedulerTask implements Runnable {

    final Object lock = new Object();

    int state = VIRGIN;
    static final int VIRGIN = 0;
    static final int SCHEDULED = 1;
    static final int CANCELLED = 2;

    TimerTask timerTask;

    protected SchedulerTask() {
    }

    public abstract void run();

    public boolean cancel() {
    synchronized(lock) {
    if (timerTask != null) {
    timerTask.cancel();
    }
    boolean result = (state == SCHEDULED);
    state = CANCELLED;
    return result;
    }
    }

    public long scheduledExecutionTime() {
    synchronized(lock) {
    return timerTask == null ? 0 : timerTask.scheduledExecutionTime();
    }
    }

    }


    就 像煮蛋計時器,Scheduler 的每一個實(shí)例都擁有 Timer 的一個實(shí)例,用于提供底層計劃。Scheduler 并沒有像實(shí)現(xiàn)煮蛋計時器時那樣使用一個單次定時器,它將一組單次定時器串接在一起,以便在由 ScheduleIterator 指定的各個時間執(zhí)行 SchedulerTask 類。

    考慮 Scheduler 上的 public schedule() 方法 —— 這是計劃的入口點(diǎn),因為它是客戶調(diào)用的方法(在 取消任務(wù) 一節(jié)中將描述僅有的另一個 public 方法 cancel())。通過調(diào)用 ScheduleIterator 接口的 next(),發(fā)現(xiàn)第一次執(zhí)行 SchedulerTask 的時間。然后通過調(diào)用底層 Timer 類的單次 schedule() 方法,啟動計劃在這一時刻執(zhí)行。為單次執(zhí)行提供的 TimerTask 對象是嵌入的 SchedulerTimerTask 類的一個實(shí)例,它包裝了任務(wù)和迭代器(iterator)。在指定的時間,調(diào)用嵌入類的 run() 方法,它使用包裝的任務(wù)和迭代器引用以便重新計劃任務(wù)的下一次執(zhí)行。reschedule() 方法與 schedule() 方法非常相似,只不過它是 private 的,并且執(zhí)行一組稍有不同的 SchedulerTask 狀態(tài)檢查。重新計劃過程反復(fù)重復(fù),為每次計劃執(zhí)行構(gòu)造一個新的嵌入類實(shí)例,直到任務(wù)或者調(diào)度程序被取消(或者 JVM 關(guān)閉)。

    類似 于 TimerTask,SchedulerTask 在其生命周期中要經(jīng)歷一系列的狀態(tài)。創(chuàng)建后,它處于 VIRGIN 狀態(tài),這表明它從沒有計劃過。計劃以后,它就變?yōu)?SCHEDULED 狀態(tài),再用下面描述的方法之一取消任務(wù)后,它就變?yōu)?CANCELLED 狀態(tài)。管理正確的狀態(tài)轉(zhuǎn)變 —— 如保證不對一個非 VIRGIN 狀態(tài)的任務(wù)進(jìn)行兩次計劃 —— 增加了 Scheduler 和 SchedulerTask 類的復(fù)雜性。在進(jìn)行可能改變?nèi)蝿?wù)狀態(tài)的操作時,代碼必須同步任務(wù)的鎖對象。

    取消任務(wù)

    取 消計劃任務(wù)有三種方式。第一種是調(diào)用 SchedulerTask 的 cancel() 方法。這很像調(diào)用 TimerTask 的 cancel()方法:任務(wù)再也不會運(yùn)行了,不過已經(jīng)運(yùn)行的任務(wù)仍會運(yùn)行完成。 cancel() 方法的返回值是一個布爾值,表示如果沒有調(diào)用 cancel() 的話,計劃的任務(wù)是否還會運(yùn)行。更準(zhǔn)確地說,如果任務(wù)在調(diào)用 cancel() 之前是 SCHEDULED 狀態(tài),那么它就返回 true。如果試圖再次計劃一個取消的(甚至是已計劃的)任務(wù),那么 Scheduler 就會拋出一個 IllegalStateException。

    取消計劃任務(wù)的第二種方式是讓 ScheduleIterator 返回 null。這只是第一種方式的簡化操作,因為 Scheduler 類調(diào)用 SchedulerTask 類的 cancel()方法。如果您想用迭代器而不是任務(wù)來控制計劃停止時間時,就用得上這種取消任務(wù)的方式了。

    第三種方式是通過調(diào)用其 cancel() 方法取消整個 Scheduler。這會取消調(diào)試程序的所有任務(wù),并使它不能再計劃任何任務(wù)。

    擴(kuò)展 cron 實(shí)用程序

    可 以將計劃框架比作 UNIX 的 cron 實(shí)用程序,只不過計劃次數(shù)的規(guī)定是強(qiáng)制性而不是聲明性的。例如,在 AlarmClock 實(shí)現(xiàn)中使用的 DailyIterator 類,它的計劃與 cron 作業(yè)的計劃相同,都是由以 0 7 * * * 開始的 crontab 項指定的(這些字段分別指定分鐘、小時、日、月和星期)。

    不過,計劃框架比 cron 更靈活。想像一個在早晨打開熱水的 HeatingController 應(yīng)用程序。我想指示它“在每個工作日上午 8:00 打開熱水,在周未上午 9:00 打開熱水”。使用 cron,我需要兩個 crontab 項(0 8 * * 1,2,3,4,5 和 0 9 * * 6,7)。而使用 ScheduleIterator 的解決方案更簡潔一些,因為我可以使用復(fù)合(composition)來定義單一迭代器。清單 7 顯示了其中的一種方法:

    清單 7. 用復(fù)合定義單一迭代器

    int[] weekdays = new int[] {
    Calendar.MONDAY,
    Calendar.TUESDAY,
    Calendar.WEDNESDAY,
    Calendar.THURSDAY,
    Calendar.FRIDAY
    };
    int[] weekend = new int[] {
    Calendar.SATURDAY,
    Calendar.SUNDAY
    };
    ScheduleIterator i = new CompositeIterator(
    new ScheduleIterator[] {
    new RestrictedDailyIterator(8, 0, 0, weekdays),
    new RestrictedDailyIterator(9, 0, 0, weekend)
    }
    );


    RestrictedDailyIterator 類很像 DailyIterator,只不過它限制為只在一周的特定日子里運(yùn)行,而一個 CompositeIterator 類取得一組 ScheduleIterators,并將日期正確排列到單個計劃中。

    有 許多計劃是 cron 無法生成的,但是 ScheduleIterator 實(shí)現(xiàn)卻可以。例如,“每個月的最后一天”描述的計劃可以用標(biāo)準(zhǔn) Java 日歷算法來實(shí)現(xiàn)(用 Calendar 類),而用 cron 則無法表達(dá)它。應(yīng)用程序甚至無需使用 Calendar 類。在本文的源代碼(請參閱 參考資料)中,我加入了一個安全燈控制器的例子,它按“在日落之前 15 分鐘開燈”這一計劃運(yùn)行。這個實(shí)現(xiàn)使用了 Calendrical Calculations Software Package,用于計算當(dāng)?shù)兀ńo定經(jīng)度和緯度)的日落時間。

    實(shí)時保證

    在編寫使用計劃的應(yīng)用程序時,一定要了解框架在時間方面有什么保證。我的任務(wù)是提前還是延遲執(zhí)行?如果有提前或者延遲,偏差最大值是多少?不幸的是,對這些問題沒有簡單的答案。不過在實(shí)際中,它的行為對于很多應(yīng)用程序已經(jīng)足夠了。下面的討論假設(shè)系統(tǒng)時鐘是正確的。

    因為 Scheduler 將計劃委托給 Timer 類,Scheduler 可以做出的實(shí)時保證與 Timer 的一樣。Timer 用 Object.wait(long) 方法計劃任務(wù)。當(dāng)前線程要等待直到喚醒它,喚醒可能出于以下原因之一:

    1.另一個線程調(diào)用對象的 notify() 或者 notifyAll() 方法。

    2.線程被另一個線程中斷。

    3.在沒有通知的情況下,線程被喚醒(稱為 spurious wakeup,Joshua Bloch 的 Effective Java Programming Language Guide 一書中 Item 50 對其進(jìn)行了描述 。

    4.規(guī)定的時間已到。

    對 于 Timer 類來說,第一種可能性是不會發(fā)生的,因為對其調(diào)用 wait() 的對象是私有的。即便如此,Timer 實(shí)現(xiàn)仍然針對前三種提前喚醒的原因進(jìn)行了保護(hù),這樣保證了線程在規(guī)定時間后才喚醒。目前,Object.wait(long) 的文檔注釋聲明,它會在規(guī)定的時間“前后”蘇醒,所以線程有可能提前喚醒。在本例中,Timer 會讓另一個 wait() 執(zhí)行(scheduledExecutionTime - System.currentTimeMillis())毫秒,從而保證任務(wù)永遠(yuǎn)不會提前執(zhí)行。任務(wù)是否會延遲執(zhí)行呢?會的。延遲執(zhí)行有兩個主要原因:線 程計劃和垃圾收集。

    Java 語言規(guī)范故意沒有對線程計劃做嚴(yán)格的規(guī)定。這是因為 Java 平臺是通用的,并針對于大范圍的硬件及其相關(guān)的操作系統(tǒng)。雖然大多數(shù) JVM 實(shí)現(xiàn)都有公平的線程調(diào)度程序,但是這一點(diǎn)沒有任何保證 —— 當(dāng)然,各個實(shí)現(xiàn)都有不同的為線程分配處理器時間的策略。因此,當(dāng) Timer 線程在分配的時間后喚醒時,它實(shí)際執(zhí)行其任務(wù)的時間取決于 JVM 的線程計劃策略,以及有多少其他線程競爭處理器時間。因此,要減緩任務(wù)的延遲執(zhí)行,應(yīng)該將應(yīng)用程序中可運(yùn)行的線程數(shù)降至最少。為了做到這一點(diǎn),可以考慮在 一個單獨(dú)的 JVM 中運(yùn)行調(diào)度程序。

    對于創(chuàng)建大量對象的大型應(yīng)用程序,JVM 花在垃圾收集(GC)上的時間會非常多。默認(rèn)情況下,進(jìn)行 GC 時,整個應(yīng)用程序都必須等待它完成,這可能要有幾秒鐘甚至更長的時間(Java 應(yīng)用程序啟動器的命令行選項 -verbose:gc 將導(dǎo)致向控制臺報告每一次 GC 事件)。要將這些由 GC 引起的暫停(這可能會影響快速任務(wù)的執(zhí)行)降至最少,應(yīng)該將應(yīng)用程序創(chuàng)建的對象的數(shù)目降至最低。同樣,在單獨(dú)的 JVM 中運(yùn)行計劃代碼是有幫助的。同時,可以試用幾個微調(diào)選項以盡可能地減少 GC 暫停。例如,增量 GC 會盡量將主收集的代價分散到幾個小的收集上。當(dāng)然這會降低 GC 的效率,但是這可能是時間計劃的一個可接受的代價。

    被計劃到什么時候?

    如 果任務(wù)本身能監(jiān)視并記錄所有延遲執(zhí)行的實(shí)例,那么對于確定任務(wù)是否能按時運(yùn)行會很有幫助。SchedulerTask 類似于 TimerTask,有一個 scheduledExecutionTime() 方法,它返回計劃任務(wù)最近一次執(zhí)行的時間。在任務(wù)的 run() 方法開始時,對表達(dá)式 System.currentTimeMillis() - scheduledExecutionTime() 進(jìn)行判斷,可以讓您確定任務(wù)延遲了多久執(zhí)行(以毫秒為單位)??梢杂涗涍@個值,以便生成一個關(guān)于延遲執(zhí)行的分布統(tǒng)計??梢杂眠@個值決定任務(wù)應(yīng)當(dāng)采取什么動 作 —— 例如,如果任務(wù)太遲了,那么它可能什么也不做。在遵循上述原則的情況下,如果應(yīng)用程序需要更嚴(yán)格的時間保證,可參考 Java 的實(shí)時規(guī)范。

    結(jié)束語

    在本文中,我介紹了 Java 定時器框架的一個簡單增強(qiáng),它使得靈活的計劃策略成為可能。新的框架實(shí)質(zhì)上是更通用的 cron —— 事實(shí)上,將 cron 實(shí)現(xiàn)為一個 ScheduleIterator 接口,用以替換單純的 Java cron,這是非常有用的。雖然沒有提供嚴(yán)格的實(shí)時保證,但是許多需要計劃定期任務(wù)的通用 Java 應(yīng)用程序都可以使用這一框架。

    參考資料

    ·下載本文中使用的 源代碼。

    ·“Tuning Garbage Collection with the 1.3.1 Java Virtual Machine”是 Sun 的一篇非常有用的文章,它給出了關(guān)于如何最小化 GC 暫停時間的提示。

    ·要獲得 developerWorks 中有關(guān) GC 的更多信息,請參閱以下文章:

    Java 理論與實(shí)踐:垃圾收集簡史” (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 理論與實(shí)踐:并發(fā)在一定程度上使一切變得簡單”(developerWorks, 2002 年 11 月)中,Brian Goetz 討論了 Doug Lea 的 util.concurrent 庫,這是一個并發(fā)實(shí)用工具類的寶庫。

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

    關(guān)于作者

    Tom White 是 Kizoom 的首席 Java 開發(fā)人員,Kizoom 是一家領(lǐng)先的英國軟件公司,提供向移動設(shè)備發(fā)送個性化旅行信息的服務(wù)??蛻舭ㄓ膰一疖嚥僮鲉T、倫敦公共交通系統(tǒng)(national train operator),以及英國國家公共汽車公司。自 1999 年成立以來,Kizoom 使用了極限編程的所有方法。自 1996 年起,Tom 一直全職編寫 Java 程序,使用了大部分標(biāo)準(zhǔn)和企業(yè) Java API,編寫了從客戶 Swing GUI 和圖形到后端消息傳送系統(tǒng)等各種應(yīng)用程序。他在劍橋大學(xué)獲得了一級榮譽(yù)學(xué)位(first class honours degree)。工作之余,Tom 喜歡逗他的小女兒開心,觀看 20 世紀(jì) 30 年代的好萊塢電影??梢酝ㄟ^ tom@tiling.org 與 Tom 聯(lián)系。

    posted on 2007-03-23 13:12 advincenting 閱讀(4548) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     

    公告

    Locations of visitors to this pageBlogJava
  • 首頁
  • 新隨筆
  • 聯(lián)系
  • 聚合
  • 管理
  • <2007年3月>
    25262728123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    統(tǒng)計

    常用鏈接

    留言簿(13)

    隨筆分類(71)

    隨筆檔案(179)

    文章檔案(13)

    新聞分類

    IT人的英語學(xué)習(xí)網(wǎng)站

    JAVA站點(diǎn)

    優(yōu)秀個人博客鏈接

    官網(wǎng)學(xué)習(xí)站點(diǎn)

    生活工作站點(diǎn)

    最新隨筆

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 九九久久国产精品免费热6| 成人毛片免费观看视频在线| 激情综合亚洲色婷婷五月APP| 亚洲精品A在线观看| 永久免费毛片在线播放| A片在线免费观看| 在线免费观看一区二区三区| 无码中文字幕av免费放dvd| h片在线播放免费高清| 国产精品亚洲精品日韩电影| 中文字幕 亚洲 有码 在线| 亚洲福利在线视频| 久久夜色精品国产亚洲| 亚洲成人一区二区| 日本无卡码免费一区二区三区| 久久久久国产精品免费看| 人妻无码中文字幕免费视频蜜桃| 亚洲乱码一区av春药高潮| 国产亚洲无线码一区二区| 亚洲欧洲久久av| 99爱视频99爱在线观看免费| 亚洲AV无码专区国产乱码电影| 日韩免费观看的一级毛片| 大学生一级毛片免费看| 日本免费高清视频| 最近免费中文字幕MV在线视频3| 搜日本一区二区三区免费高清视频| 亚洲日韩乱码中文无码蜜桃臀| 亚洲AV无码久久精品蜜桃| 免费成人av电影| 在线免费观看a级片| 在线观看免费视频资源| 国产妇乱子伦视频免费| 青青草无码免费一二三区| 久久w5ww成w人免费| 久久国产乱子伦精品免费看| 久久久久国色av免费看| 国产无遮挡无码视频免费软件 | 亚洲精品视频观看| 国产精品免费一区二区三区四区| 香蕉视频亚洲一级|