9

チャット アプリケーションの新しいメッセージをロング ポーリングするために、Timer と TimerTask を使用しています。「わずかに」異なる 2 つの可能性を検討したいと思います。

1 :ローカル変数として宣言されたタイマー

public List<MessageBean> getLastMessages(...) {
    [...]
    Timer timer = new Timer(true); //**Timer declared as local variable**
    while (someCondiction) {
        MessagesTimerTask returnMessagesTask = new MessagesTimerTask([...]);
        timer.schedule(returnMessagesTask, 6000);
        synchronized (listMessageBean) {
            listMessageBean.wait();
            //notify is called in the MessagesTimerTask which extends TimerTask
        }
    }
}

*問題:メソッドを呼び出すたびに、[Timer-1]、[Timer-2] などの新しいスレッドが作成されていることがわかります。Eclipse のデバッグ ウィンドウでは、getLastMessagesの後でもすべて実行されているように見えます。 (..)実行を終了し、クライアントに値を返します。タイマーが実際にスレッドを使用している場合、これは大きな問題を引き起こす可能性があり、いくつかのトランザクションの後、サーバーは最終的にすべてのマシン リソースを消費します。

2 :ローカル フィールドとして宣言されたタイマー

private final Timer timer = new Timer(true); //**Timer declared as local field**

public List<MessageBean> getLastMessages(...) {
    [...]
    while (someCondiction) {
        MessagesTimerTask returnMessagesTask = new MessagesTimerTask([...]);
        timer.schedule(returnMessagesTask, 6000);
        synchronized (listMessageBean) {
            listMessageBean.wait();
            //notify is called in the MessagesTimerTask which extends TimerTask
        }
    }
}

*問題:メソッドを呼び出すたびに同じスレッドが使用される [Thread-1] が、2 つの連続した呼び出しを行うかどうかわからない場合、後者は前者をキャンセル/オーバーライドします (クラスは @Autowired by spring です) ) ?

助言がありますか ?ありがとうございました。

4

1 に答える 1

8

メソッドのソースコードは次のとおりです。schedule

190       public void schedule(TimerTask task, long delay) {
191           if (delay < 0)
192               throw new IllegalArgumentException("Negative delay.");
193           sched(task, System.currentTimeMillis()+delay, 0);
194       }

そしてsched方法:

386       private void sched(TimerTask task, long time, long period) {
387           if (time < 0)
388               throw new IllegalArgumentException("Illegal execution time.");
389   
390           // Constrain value of period sufficiently to prevent numeric
391           // overflow while still being effectively infinitely large.
392           if (Math.abs(period) > (Long.MAX_VALUE >> 1))
393               period >>= 1;
394   
395           synchronized(queue) {
396               if (!thread.newTasksMayBeScheduled)
397                   throw new IllegalStateException("Timer already cancelled.");
398   
399               synchronized(task.lock) {
400                   if (task.state != TimerTask.VIRGIN)
401                       throw new IllegalStateException(
402                           "Task already scheduled or cancelled");
403                   task.nextExecutionTime = time;
404                   task.period = period;
405                   task.state = TimerTask.SCHEDULED;
406               }
407   
408               queue.add(task);
409               if (queue.getMin() == task)
410                   queue.notify();
411           }
412       }

ここから、タスクを内部に格納するためにキューが使用されていることがはっきりとわかります。つまり、後のタスクは前のタスクを上書きしません。ファイル内のメソッドも確認するmainLoopと、スケジュール時刻順にキューからタスクを 1 つずつ取り出して実行していることがわかります。

Timerしたがって、同じオブジェクトに対して複数のタスクをスケジュールしても問題はありません。

補足として、 Java 1.5 以降Timerで使用可能なものに置き換えることを検討してください。ScheduledThreadPoolExecutor

于 2012-08-18T05:42:20.083 に答える