計画タスクScheduledExecutorServiceの使用概要


Javaにおける計画タスクTimerツールクラスは、タイマや計画タスクの機能により所定時間または時間間隔でタスクを実行することを実現するが、Timerツールクラスはプールpoolではなくキューでスレッドを管理するため、高同時性では実行効率が低い、新しいJDKでは、効率とタイミングのタスクを解決するためのScheduledExecutorServiceオブジェクトの機能が提供されています.
 
1.ScheduledExecutorServiceの使用
クラスScheduledExecutorServiceの主な役割は、タイミングタスクとスレッドプール機能を組み合わせて使用できることです.実装クラスScheduledThreadPoolExecutorの親インタフェースかExecutorか、親クラスはThreadPoolExecutorであり、その一部の方法は親クラスThreadPoolExecutorが提供し、サブクラスScheduledThreadPoolExecutorで書き換えたものであり、例えばsubmit()リロード方法やshutdown()などの方法である.
2.ScheduledThreadPoolExecutor Callableによる運転遅延
Callableインタフェースを用いてタスク遅延運転の実験を行い,値を返す機能を持つ.
package mycallable;

import java.util.concurrent.Callable;

public class MyCallableA implements Callable {
	@Override
	public String call() throws Exception {
		try {
			System.out.println("callA begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
			Thread.sleep(3000);
			System.out.println("callA   end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "returnA";
	}
}
package mycallable;

import java.util.concurrent.Callable;

public class MyCallableB implements Callable {
	@Override
	public String call() throws Exception {
		System.out.println("callB begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
		System.out.println("callB   end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
		return "returnB";
	}
}
package test.run;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import mycallable.MyCallableA;
import mycallable.MyCallableB;

public class Run1 {
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		try {
			List callableList = new ArrayList();
			callableList.add(new MyCallableA());
			callableList.add(new MyCallableB());
			//     newSingleThreadScheduledExecutor
			//                
			ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
			ScheduledFuture futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
			ScheduledFuture futureB = executor.schedule(callableList.get(1), 4L, TimeUnit.SECONDS);
			System.out.println("          X=" + System.currentTimeMillis());
			System.out.println("   A:" + futureA.get());
			System.out.println("   B:" + futureB.get());
			System.out.println("          Y=" + System.currentTimeMillis());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
}
package test.run;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import mycallable.MyCallableA;
import mycallable.MyCallableB;

public class Run2 {
	public static void main(String[] args) {
		try {
			List callableList = new ArrayList();
			callableList.add(new MyCallableA());
			callableList.add(new MyCallableB());
			//     newScheduledThreadPool(corePoolSize >1)
			//         corePoolSize            
			ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
			ScheduledFuture futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
			ScheduledFuture futureB = executor.schedule(callableList.get(1), 4L, TimeUnit.SECONDS);
			System.out.println("          X=" + System.currentTimeMillis());
			System.out.println("   A:" + futureA.get());
			System.out.println("   B:" + futureB.get());
			System.out.println("          Y=" + System.currentTimeMillis());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
}
package test.run;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import mycallable.MyCallableA;
import mycallable.MyCallableB;

public class Run3 {
	public static void main(String[] args) {
		try {
			List callableList = new ArrayList();
			callableList.add(new MyCallableA());
			callableList.add(new MyCallableB());
			//     newScheduledThreadPool(1)
			//                
			ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
			ScheduledFuture futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
			ScheduledFuture futureB = executor.schedule(callableList.get(1), 4L, TimeUnit.SECONDS);
			System.out.println("          X=" + System.currentTimeMillis());
			System.out.println("   A:" + futureA.get());
			System.out.println("   B:" + futureB.get());
			System.out.println("          Y=" + System.currentTimeMillis());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
}

(単一タスクスケジューリング)XからYまでの実行時間は7秒,ブロックポイントはget()メソッドである.public ScheduledFuture schedule(Callable callable,long delay,TimeUnit unit)メソッドinvokeAllの2番目のパラメータは、複数のタスクで同時に時間を消費し、1つのタスクが実行されてから4秒も実行を待つ効果ではありません.1番目のタスクは計画タスクから実行終了まで7秒かかるため、2番目のタスクは実は4秒目に実行されたいと考えられ、単一タスクの計画タスクプールであるため、2番目のタスクの実行時間は3秒遅れている.newScheduledThreadPool(poolSize)の書き方で作成されたタスクプールでも単一タスクです.
3.ScheduledThreadPoolExecutor Runnableによる遅延運転
Runnableインタフェースを使用した戻り値のない計画タスクのインスタンス
package mycallable;

public class MyRunnableA implements Runnable {
	@Override
	public void run() {
		try {
			System.out
					.println("runnableA begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
			Thread.sleep(3000);
			System.out
					.println("runnableA   end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
package mycallable;

public class MyRunnableB implements Runnable {
	@Override
	public void run() {
		System.out.println("runnableB begin " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
		System.out.println("runnableB   end " + Thread.currentThread().getName() + " " + System.currentTimeMillis());
	}
}
package test.run;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnableA;
import mycallable.MyRunnableB;

public class Run {
	public static void main(String[] args) {
		List runnableList = new ArrayList();
		runnableList.add(new MyRunnableA());
		runnableList.add(new MyRunnableB());
		ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

		System.out.println("     X=" + System.currentTimeMillis());
		executor.schedule(runnableList.get(0), 0L, TimeUnit.SECONDS);
		executor.schedule(runnableList.get(1), 0L, TimeUnit.SECONDS);
		System.out.println("     Y=" + System.currentTimeMillis());

	}
}

4.運転を遅延して戻り値を取得する
package mycallable;

import java.util.concurrent.Callable;

public class MyCallableA implements Callable {
	public String call() throws Exception {
		System.out.println("a call run =" + System.currentTimeMillis());
		return "returnA";
	}
}
package test.run;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import mycallable.MyCallableA;

public class Run {
	public static void main(String[] args) {
		try {
			List callableList = new ArrayList();
			callableList.add(new MyCallableA());
			ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
			System.out.println("X=" + System.currentTimeMillis());
			ScheduledFuture futureA = executor.schedule(callableList.get(0), 4L, TimeUnit.SECONDS);
			System.out.println(futureA.get() + "   A=" + System.currentTimeMillis());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
}

5.scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)メソッドによる周期的な実行(タスクタイムアウトの効果がある)
5.1インタフェースscheduleAtFixedRateプロトタイプ定義及びパラメータ説明
command:実行スレッド
initialDelay:初期化遅延
period:最小間隔の実行を2回開始
unit:タイミング単位
package mycallable;

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		try {
			System.out.println(
					"      begin =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
			Thread.sleep(4000);
			System.out.println(
					"        end =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
package test.run;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

public class Run {
	public static void main(String[] args) {
		ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
		System.out.println("           X=" + System.currentTimeMillis());
		executor.scheduleAtFixedRate(new MyRunnable(), 1, 2, TimeUnit.SECONDS);
		System.out.println("           Y=" + System.currentTimeMillis());
	}
}

scheduleAtFixedRate()メソッドが返すScheduledFutureオブジェクトには戻り値が得られません.つまり、scheduleAtFixedRate()メソッドは戻り値を得る機能を持ちませんが、schedule()メソッドは戻り値を得ることができます.したがって、scheduleAtFixedRate()メソッドを使用してタスクの繰り返し実行の効果を実現する場合は、FutureTaskクラスでは繰り返し実行の効果が得られないため、カスタムRunnableインタフェースの実装クラスと組み合わせる必要があります.
6.scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)メソッドを使用して周期的な実行を実現する(この方法はタイムアウトと非タイムアウトがない場合)
command:実行スレッド
initialDelay:初期化遅延
period:前回実行終了から次回実行開始までの間隔(間隔実行遅延時間)
unit:タイミング単位
package mycallable;

public class MyRunnable implements Runnable {

	@Override
	public void run() {
		try {
			System.out.println(
					"      begin =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
			Thread.sleep(4000);
			System.out.println(
					"        end =" + System.currentTimeMillis() + " ThreadName=" + Thread.currentThread().getName());
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}
package test.run;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

public class Run {
	public static void main(String[] args) {
		ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
		System.out.println("           X=" + System.currentTimeMillis());
		executor.scheduleWithFixedDelay(new MyRunnable(), 1, 2, TimeUnit.SECONDS);
		System.out.println("           Y=" + System.currentTimeMillis());
	}
}

7.getQueue()とremove()メソッドの使用
メソッドgetQueue()の役割は、キュー内のタスクを取得することですが、これらのタスクは将来実行され、実行中のタスクはこのキューにありません.scheduleAtFixedRate()とscheduleWithFixedDelay()の2つのメソッドを使用して周期的な実行タスクを実装する場合、将来実行するタスクはすべてこのキューに格納されます.
package mycallable;

public class MyRunnable implements Runnable {

	private String username;

	public MyRunnable(String username) {
		super();
		this.username = username;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	public void run() {
		System.out.println("run! username=" + username + " " + Thread.currentThread().getName());
	}

}
package test.run;

import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

public class Run1 {
	public static void main(String[] args) {

		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);

		Runnable runnable1 = new MyRunnable("A");
		Runnable runnable2 = new MyRunnable("B");
		Runnable runnable3 = new MyRunnable("C");
		Runnable runnable4 = new MyRunnable("D");
		Runnable runnable5 = new MyRunnable("E");

		System.out.println(runnable1.hashCode());
		System.out.println(runnable2.hashCode());
		System.out.println(runnable3.hashCode());
		System.out.println(runnable4.hashCode());
		System.out.println(runnable5.hashCode());

		executor.scheduleAtFixedRate(runnable1, 10, 2, TimeUnit.SECONDS);
		executor.scheduleAtFixedRate(runnable2, 10, 2, TimeUnit.SECONDS);
		executor.scheduleAtFixedRate(runnable3, 10, 2, TimeUnit.SECONDS);
		executor.scheduleAtFixedRate(runnable4, 10, 2, TimeUnit.SECONDS);
		executor.scheduleAtFixedRate(runnable5, 10, 2, TimeUnit.SECONDS);

		System.out.println("");

		BlockingQueue queue = executor.getQueue();
		Iterator iterator = queue.iterator();
		while (iterator.hasNext()) {
			Runnable runnable = (Runnable) iterator.next();
			System.out.println("    :" + runnable);
		}
	}
}
package test.run;

import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

public class Run2 {
	public static void main(String[] args) throws InterruptedException {

		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);

		Runnable runnable1 = new MyRunnable("A");
		Runnable runnable2 = new MyRunnable("B");

		ScheduledFuture future1 = executor.scheduleAtFixedRate(runnable1, 0, 2, TimeUnit.SECONDS);
		Thread.sleep(1000);
		ScheduledFuture future2 = executor.scheduleAtFixedRate(runnable2, 10, 2, TimeUnit.SECONDS);
		Thread.sleep(5000);
		System.out.println(executor.remove((Runnable) future2));
		System.out.println("");

		BlockingQueue queue = executor.getQueue();
		Iterator iterator = queue.iterator();
		while (iterator.hasNext()) {
			Runnable runnable = (Runnable) iterator.next();
			System.out.println("    :" + runnable);
		}
	}
}

8.方法setExecute ExistingDelayedTasksAfterShutdownPolicy()の使用
メソッドsetExecute ExistingDelayedTasksAfterShutdownPolicy()の役割は、S h e d u l edThreadPoolExecutorに対してshutdown()メソッドが実行された場合、タスクが実行されるかどうかです.デフォルト値はtrueです.つまり、shutdown()メソッドが呼び出された場合、タスクが実行されるかどうかです.setExecuteExistingDelayedTasksAfterShutdownPolicy(false)が使用されている場合、タスクは実行されません.
package mycallable;

public class MyRunnable implements Runnable {

	private String username;

	public MyRunnable(String username) {
		super();
		this.username = username;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	public void run() {
		System.out.println("run! username=" + username + " " + Thread.currentThread().getName() + " "
				+ System.currentTimeMillis());
	}
}
package test.run;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

/**
 *   shutdown()        
 * @author linhaiy
 *
 */
public class Run1 {
	public static void main(String[] args) throws InterruptedException {
		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
		Runnable runnable1 = new MyRunnable("A");
		Runnable runnable2 = new MyRunnable("B");
		executor.schedule(runnable1, 3, TimeUnit.SECONDS);
		executor.shutdown();
		System.out.println("  shutdown ");
	}
}
package test.run;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

/**
 *        ,     
 * @author linhaiy
 *
 */
public class Run2 {
	public static void main(String[] args) {
		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
		Runnable runnable1 = new MyRunnable("A");
		Runnable runnable2 = new MyRunnable("B");
		executor.schedule(runnable1, 3, TimeUnit.SECONDS);
		executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
		executor.shutdown();
		System.out.println("  shutdown ");
	}
}

メソッドsetExecute ExistingDelayedTasksAfterShutdownPolicy()はschedule()メソッドとshutdown()メソッドと併用できますが、setExecute ExistingDelayedTasksAfterShutdownPolicy()メソッドはscheduleAtFixedRate()メソッドとscheduleWithFixedDelay()メソッドと併用できません.では、shutdownがスレッドプールを閉じた後も、プール内のタスクが繰り返し実行されるようにするには、scheduleAtFixedRate()メソッドとscheduleWithFixedDelay()メソッドをs e t E c u t e ExistingDelayedTasksAfterShutdownPolicy()メソッドと組み合わせて使用します.
9.方法s t e c o n t i n ueExistingPeriodicTasksAfterShutdownPolicy()
メソッドs t e c o n t i n u e S u t i n g P e r iodicTasksAfterShutdownPolicy()転送trueの役割は、scheduleAtFixedRate()メソッドまたはscheduleWithFixedDelay()メソッドを使用する場合、ScheduledThreadPoolExecutorオブジェクトのshutdown()メソッドを呼び出すと、タスクは継続的に実行され、falseに転送されるとタスクは実行されず、プロセスは破棄されます.scheduleAtFixedRate()を使用してshutdown()メソッドと組み合わせてタスクの継続的な実行の効果を実現する場合は、s t e t C o n i n ueExistingPeriodicTasksAfterShutdownPolicy(true)コードを使用する必要があります.
package mycallable;

public class MyRunnable implements Runnable {

	private String username;

	public MyRunnable(String username) {
		super();
		this.username = username;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	public void run() {
		System.out.println("run! username=" + username + " " + Thread.currentThread().getName() + " "
				+ System.currentTimeMillis());
	}
}
package test.run;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

public class Run1 {
	public static void main(String[] args) {
		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
		Runnable runnable1 = new MyRunnable("A");
		executor.scheduleAtFixedRate(runnable1, 1, 2, TimeUnit.SECONDS);
		executor.shutdown();
		System.out.println("   shutdown!");
	}
}
package test.run;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import mycallable.MyRunnable;

public class Run2 {
	public static void main(String[] args) {
		ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
		Runnable runnable1 = new MyRunnable("A");
		executor.scheduleAtFixedRate(runnable1, 1, 2, TimeUnit.SECONDS);
		executor.setContinueExistingPeriodicTasksAfterShutdownPolicy(true);
		executor.shutdown();
		System.out.println("   shutdown!");
	}
}

10.cancel(boolean)とsetRemoveOnCancelPolicy()メソッドの使用
10.1メソッドcancel(boolean)の役割タスクをキャンセルするかどうかを設定します.
10.2メソッドsetRemoveOnCancelPolicy(boolean)の役割は、キャンセルしたタスクをキューからクリアするかどうかを設定します.
10.3 cancel()メソッドを実行すると、タスクは正常にキャンセルされましたが、キューに存在します.
10.4キュー内のタスクが正常にキャンセルされ、タスクも実行されなくなりました.
10.5実行中のタスクは停止できますが、if(Thread.currentThread().isInterrupted()==true)と組み合わせて判断します.
10.6 setRemoveOnCancelPolicy(true)コードを使用してcancel(true)を結合すると、キュー内のタスクが削除されます.
まとめ:スレッドプールThreadPoolExecutorに基づくS h e d u l edThreadPoolExecutor計画タスク実行プールオブジェクトについて説明します.これにより、計画タスクスレッドプールを効率的に実現し、Threadオブジェクトを繰り返し作成することなく、実行効率を向上させることができます.このような機能は、間隔運転の機能もサポートされています.