私はJava whileループを15秒間繰り返す。 whileループ署名の時間。
もっと良い方法はありますか?
この設計は、15秒間何をしたいかによって異なります。最も可能性の高い2つのケースは、「Xを15秒間ごとに実行する」または「Xが発生するか、15秒間早く来るかのどちらかを待つ」ことで、コードが大きく異なります。
これは繰り返されませんが、15秒間何もしない場合は、はるかに効率的です(何もしない場合のCPUの無駄が少なくなります)。
本当に15秒間ループしたい場合は、コードに時間がかからない限り、ソリューションは問題ありません。何かのようなもの:
long t= System.currentTimeMillis();
long end = t+15000;
while(System.currentTimeMillis() < end) {
// do something
// pause to avoid churning
Thread.sleep( xxx );
}
実行中のコードが正確に15秒後に中断されるようにするには、マルチスレッドソリューションが必要です。多くの便利なオブジェクトについては、 Java.util.concurrent をご覧ください。ロックするほとんどのメソッド(wait()など)にはタイムアウト引数があります。 セマフォ は、まさに必要なことをするかもしれません。
他のポスターで既に述べたように、スレッドをしばらく一時停止させたい場合は、Thread.sleep()
を使用してください。
スレッドに何かをさせたいが、しばらくしてから停止させたい場合は、次のようなものを使用します。
class Foo implements Runnable {
private volatile boolean killed = false;
public void run() {
while (!killed) {
try { doOnce(); } catch (InterruptedException ex) { killed = true; }
}
}
public void kill() { killed = true; }
private void doOnce() throws InterruptedException { /* .. */ }
}
メインスレッドから、次の操作を行います。
Foo foo = new Foo();
Thread thread = new Thread(foo);
thread.start();
/* when you want to stop it */
foo.kill();
thread.interrupt();
これを試して:
public class SleepMessages {
public static void main(String args[]) throws InterruptedException {
String importantInfo[] = {
"Mares eat oats",
"Does eat oats",
"Little lambs eat ivy",
"A kid will eat ivy too"
};
for (int i = 0; i < importantInfo.length; i++) {
//Pause for 15 seconds
Thread.sleep(15000);
//Print a message
System.out.println(importantInfo[i]);
}
}
}
詳細: ここ
現在の時間が停止したいポイントよりも大きいかどうかを確認することもできますが、それ以外の場合は長時間実行している可能性がありますが、一般的なアプローチは問題ないようです。
別の方法は、15秒経過後にフラグを設定するタイマー/スレッドを実行することです。このフラグはvolatileとしてマークする必要があります。そうしないと、ループで値の変更が発生しないことがあります。
効率を重視する場合、どちらがより高価で、ループごとにシステム時間を取得するか、揮発性変数にアクセスするかを選択できますか?どちらがより効率的かはわかりません-それが本当に重要な場合、ベンチマークすることができます。
シンプルで保守可能なコードの場合、タイマーチェックアプローチを選択します。
long endTime = System.currentTimeMillis() + 15000
while (System.currentTimeMillis() < endTime) {
//loop
}
AOPと _@Timeable
_ を jcabi-aspects (私は開発者です)から使用できます:
_@Timeable(limit = 1, unit = TimeUnit.SECONDS)
String load(String resource) {
// do this check regularly:
if (Thread.currentThread.isInterrupted()) {
throw new IllegalStateException("time out");
}
// execution as normal
}
_
時間制限に達すると、スレッドはinterrupted()
フラグをtrue
に設定し、この状況を正しく処理して実行を停止するのはあなたの仕事です。
ここに私の提案があり、それは私のためにうまく機能しています:)
StoppingTime = 15 ;
int loop = 1;
long StartTime = System.currentTimeMillis() / 1000 ;
for (int i=0; i<loop; ++i) {
// your code here
loop++;
if (((System.currentTimeMillis()/1000) - StartTime) > StoppingTime)
loop=0;
}
Java.util.concurrent アプローチについては、 Chapter 6 of Java Concurrency in Practice (セクション6.3.7時間制限の設定タスク、131ページ)。
コード例: 時間予算で広告を取得します。
任意のループサイズのない@Tom Hawtinに似たソリューション。
final long end = System.nanoTime() + 15 * 1000 * 1000 * 1000L;
int loop = 1;
do {
for (int i=0; i<loop; ++i) {
...
}
loop++;
} while (System.nanoTime() < end);
この場合、内側のループのサイズは小さくなりますが、ループが特に速い場合はサイズが大きくなります。十分に遅い場合は、1回だけ反復する可能性があります。
ループに適切な処理を行わせたいと仮定すると、揮発性フラグをチェックする方が速くなることがあります。別のスレッドに15秒待機(またはタイマーを使用)してから設定します。
あるいは、ループ本体にかかるおおよその時間を知っている場合は、たとえば数百回実行して、外側のループで時間チェックを行います。
final long start = System.nanoTime();
do {
for (int i=0; i<200, ++i) {
...
}
} while (System.nanoTime()-start < 15L*1000L*1000L*1000L);
System.nanoTime
shouldシステムクロックの変更に混乱しないでください。長いリテラル番号の使用は重要です。
別のスレッドを停止したり、ループの状態を変更したりするTimerTaskのスケジューリングに興味があるかもしれません。
タイトループで現在時刻を確認しないでください。
そうしないと、ラップトップを持っている人は、過熱したCPUによってラップを焼けてしまいます。これが実際に起こっているという話を聞きました。
Thread.sleep(xxx)を回避するタイマークラスでこれを行うことをお勧めします。方法。
例えば:
import Java.util.Timer;
import Java.util.TimerTask;
public class TimerExample {
private int globalTimer = 0;
private int limitTimer = 15;
public static void main(String[] args) {
new TimerExample();
}
public TimerExample() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
globalTimer++;
// DO YOUR CODE HERE
System.out.println("running");
if (globalTimer == limitTimer) {
timer.cancel();
}
}
}, 0, 1000);
}
}