JAvaのスレッドエフェクタのまとめ!

9539 ワード

大量のスレッドの実行が必要な場合、スレッドの作成、実行、破棄を繰り返すことは避けられないが、明示的なこれらの操作自体はCPUを消費しているため、スレッドプールが良い例であるように、javaはスレッドの管理を提供するために多くのExecutorを提供している.
1.ThreadPoolExecutor
以下のプログラムはThreadPoolExetorを利用して10個のタスクを実行することをシミュレートした.
public class Program{
	public static void main(String[] agrs){
		Server s=new Server();
		for(int i=0;i<10;i++){
			Task task=new Task(new Date(),"task"+i);
			s.executeTask(task);
		}
		s.endServer();
	}
}

class Task implements Runnable{
	private Date initDate;
	private String name;
	public Task(Date initDate,String name){
		this.initDate=initDate;
		this.name=name;
	}
	@Override
	public void run(){
		System.out.printf("%s: Task %s: Created on: %s
",Thread.currentThread().getName(),name,initDate); System.out.printf("%s: Task %s: Started on: %s
",Thread.currentThread().getName(),name,new Date()); try { Long duration=(long)(Math.random()*10); System.out.printf("%s: Task %s: Doing a task during %d seconds
",Thread.currentThread().getName(),name,duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Task %s: Finished on: %s
",Thread.currentThread().getName(),name,new Date()); } } class Server{ private ThreadPoolExecutor executor; public Server(){ executor=(ThreadPoolExecutor)Executors.newCachedThreadPool(); } public void executeTask(Task task){ System.out.println("a new task has arrived"); executor.execute(task); System.out.printf("Server: Pool Size: %d Active Count: %d Completed Tasks: %d
",executor.getPoolSize(),executor.getActiveCount(),executor.getCompletedTaskCount()); } public void endServer(){ executor.shutdown(); } }

実行結果は次のとおりです.
a new task has arrived pool-1-thread-1: Task task0: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-1: Task task0: Started on: Wed Feb 12 14:54:12 CST 2014 Server: Pool Size: 1  Active Count: 1  Completed Tasks: 0 pool-1-thread-1: Task task0: Doing a task during 4 seconds a new task has arrived Server: Pool Size: 2  Active Count: 1  Completed Tasks: 0 a new task has arrived pool-1-thread-2: Task task1: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-2: Task task1: Started on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-3: Task task2: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-3: Task task2: Started on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-3: Task task2: Doing a task during 1 seconds Server: Pool Size: 3  Active Count: 2  Completed Tasks: 0 a new task has arrived pool-1-thread-2: Task task1: Doing a task during 3 seconds pool-1-thread-4: Task task3: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-4: Task task3: Started on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-4: Task task3: Doing a task during 3 seconds Server: Pool Size: 4  Active Count: 3  Completed Tasks: 0 a new task has arrived Server: Pool Size: 5  Active Count: 4  Completed Tasks: 0 a new task has arrived pool-1-thread-5: Task task4: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-6: Task task5: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-6: Task task5: Started on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-6: Task task5: Doing a task during 1 seconds Server: Pool Size: 6  Active Count: 5  Completed Tasks: 0 a new task has arrived pool-1-thread-5: Task task4: Started on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-7: Task task6: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-7: Task task6: Started on: Wed Feb 12 14:54:12 CST 2014 Server: Pool Size: 7  Active Count: 6  Completed Tasks: 0 a new task has arrived pool-1-thread-7: Task task6: Doing a task during 0 seconds pool-1-thread-5: Task task4: Doing a task during 6 seconds pool-1-thread-7: Task task6: Finished on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-8: Task task7: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-8: Task task7: Started on: Wed Feb 12 14:54:12 CST 2014 Server: Pool Size: 8  Active Count: 7  Completed Tasks: 0 pool-1-thread-8: Task task7: Doing a task during 2 seconds a new task has arrived pool-1-thread-7: Task task8: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-7: Task task8: Started on: Wed Feb 12 14:54:12 CST 2014 Server: Pool Size: 8  Active Count: 7  Completed Tasks: 1 a new task has arrived pool-1-thread-7: Task task8: Doing a task during 6 seconds Server: Pool Size: 9  Active Count: 8  Completed Tasks: 1 pool-1-thread-9: Task task9: Created on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-9: Task task9: Started on: Wed Feb 12 14:54:12 CST 2014 pool-1-thread-9: Task task9: Doing a task during 8 seconds pool-1-thread-3: Task task2: Finished on: Wed Feb 12 14:54:13 CST 2014 pool-1-thread-6: Task task5: Finished on: Wed Feb 12 14:54:13 CST 2014 pool-1-thread-8: Task task7: Finished on: Wed Feb 12 14:54:14 CST 2014 pool-1-thread-2: Task task1: Finished on: Wed Feb 12 14:54:15 CST 2014 pool-1-thread-4: Task task3: Finished on: Wed Feb 12 14:54:15 CST 2014 pool-1-thread-1: Task task0: Finished on: Wed Feb 12 14:54:16 CST 2014 pool-1-thread-5: Task task4: Finished on: Wed Feb 12 14:54:18 CST 2014 pool-1-thread-7: Task task8: Finished on: Wed Feb 12 14:54:18 CST 2014 pool-1-thread-9: Task task9: Finished on: Wed Feb 12 14:54:20 CST 2014
注意:
1.RunnableオブジェクトをExecutorに入れて実行する場合、実行が完了したらアクチュエータを閉じることを忘れないでください.そうでないと、エフェクタの永続的な実行によってプログラムが終了しない(デーモンスレッドが終了しない場合、プログラムは終了しない).2.エフェクタがスレッド管理能力が優れているからといって、大量のスレッドをスレッドに入れて実行することはできないし、システムを引きずることもある.初期化時にエフェクタがスレッドを作成する容量を指定することもできます.例えば、
executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(int number);
 
2.Callable
Callbaleインタフェースは、主にスレッドの実行結果を返すことができます.例えば、配列をソートするために複数のスレッドを開いた場合、各スレッドが実行するアルゴリズムが異なる場合、もちろん、最初のソートが完了した時間(最適アルゴリズム)を得ることを望んでいます.あるいは、各アルゴリズムが返す時間を知る必要があります.このような問題は、Callableを借りて、以下のコードがユーザー名とパスワードの検証をシミュレートし、ランダムに結果を返す必要があります.コードは以下の通りです.
public class Program{
	public static void main(String[] agrs){
		String username="fly";
		String pwd="123456";
		UserValidator v1=new UserValidator("v1");
		UserValidator v2=new UserValidator("v2");
		TaskValidator t1=new TaskValidator(v1,username,pwd);
	  TaskValidator t2=new TaskValidator(v2,username,pwd);
    List<TaskValidator> taskList=new ArrayList<TaskValidator>();
		taskList.add(t1);
		taskList.add(t2);
		ExecuteService es=(ExecuteService)Executors.newCachedThreadPool();
		String result;
		try {
			result = executor.invokeAny(taskList);
			System.out.printf("Main: Result: %s
",result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } executor.shutdown(); } } class UserValidator{ private String name; public UserValidator(String name){ this.name=name; } public boolean validate(String name,String pwd){ Random random=new Random(); try { long duration=(long)(Math.random()*10); System.out.printf("Validator %s: Validating a user during %d seconds
",this.name,duration); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { return false; } return random.nextBoolean(); } public String getName(){ return name; } } class TaskValidator implements Callable<String>{ private UserValidator validator; private String user; private String pwd; public TaskValidator(UserValidator validator,String user,String pwd ){ this.validator=validator; this.user=user; this.pwd=pwd; } @Override public String call() throws Exception{ if (!validator.validate(user, password)) { System.out.printf("%s: The user has not been found
",validator.getName()); throw new Exception("Error validating user"); } System.out.printf("%s: The user has been found
",validator.getName()); return validator.getName(); } }

Callable実装の手順は、Executorを直接呼び出すのとあまり変わらないが、唯一異なるのは、すべてのタスクをリストに入れる必要があり、リストの要素タイプは「?extends Callable」でなければならない.次に、上記のコードのようなinvokeAnyを呼び出します(ここでは、最初のタスクを返す結果と、invokeAllがすべての結果を1つのセットとして返すことができるなどの他の方法があります).
3.ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutorはタスクの実行を遅らせることができ、以下のプログラムは5つのタスクを開き、それぞれ1、2、3、4、5秒後に自動的に起動し、コードは以下の通りである.
public class Program{
	public static void main(String[] agrs){
		ScheduledThreadPoolExecutor executor=(ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);
		System.out.printf("Main: Starting at: %s
",new Date()); for (int i=0; i<5; i++) { Task task=new Task("Task "+i); executor.schedule(task,i+1 , TimeUnit.SECONDS); } executor.shutdown(); try { executor.awaitTermination(10, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Main: Ends at: %s
",new Date()); } } class Task implements Callable<String>{ private String name; public Task(String name){ this.name=name; } @Override public String call() throws Exception{ System.out.printf("%s: Starting at : %s
",name,new Date()); return "Hello, world"; } }

ScheduledThreadPoolExecutorがdelayを完了する効果は主に、schedule(Callablecallable,long delay,TimeUnit)という関数によって達成され、最初のパラメータはRunnableオブジェクトであってもよい.shutdown()は、仮想マシンにエフェクタを閉じるように通知するだけですが、異常が発生すると処理できないため、awaitTerimination(long time,TimeUnit)を利用してすべてのタスクの完了を待つ必要があります.shutdown+awaitTerminationは優雅にexecutorを閉じる方法です.