Java多线程之ExecutorService.invokeAny()

方法描述:

    /**
     * Executes the given tasks, returning the result
     * of one that has completed successfully (i.e., without throwing
     * an exception), if any do. Upon normal or exceptional return,
     * tasks that have not completed are cancelled.
     * The results of this method are undefined if the given
     * collection is modified while this operation is in progress.
     *
     * @param tasks the collection of tasks
     * @param <T> the type of the values returned from the tasks
     * @return the result returned by one of the tasks
     * @throws InterruptedException if interrupted while waiting
     * @throws NullPointerException if tasks or any element task
     *         subject to execution is {@code null}
     * @throws IllegalArgumentException if tasks is empty
     * @throws ExecutionException if no task successfully completes
     * @throws RejectedExecutionException if tasks cannot be scheduled
     *         for execution
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

  方法说明:使用invokeAny()方法,当任意一个线程找到结果之后,立刻终结【中断】所有线程。

执行结果可能会有以下三种情况:

  • 任务都执行成功,使用过第一个任务返回的结果。
  • 任务都失败了,抛出Exception,invokeAny方法将抛出ExecutionException。
  • 部分任务失败了,会使用第一个成功的任务返回的结果。

玩具代码:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

//使用invokeAny()方法,当任意一个线程找到结果之后,立刻终结【中断】所有线程
public class UserValidator {
	
	private String name;
	public UserValidator(String name){
		this.name = name;
	}
	
	//Mock验证过程,有可能会抛出异常
	public boolean validate(String name ,String password){
		Random random = new Random();
		try{
			long duration = (long)(Math.random()*10);
			System.out.printf("Validator %s: Validating a user during %d seconds \n", this.name,duration);
			TimeUnit.SECONDS.sleep(duration);
		}catch(InterruptedException e){
			e.printStackTrace();
			return false;
		}
		return random.nextBoolean();
	}
	
	public String getName(){
		return name;
	}
	
	public static class TaskValidator implements Callable<String>{
		
		private UserValidator validator;
		private String name;
		private String password;
		
		public TaskValidator(UserValidator validator,String name,String password){
			this.validator = validator;
			this.name = name;
			this.password = password;
		}

		@Override
		public String call() throws Exception {
			
			if(!validator.validate(name, password)){
				System.out.printf("%s : The user has not been found \n", validator.getName());
				throw new Exception("Error validating user");
			}
			
			System.out.printf("%s: The user has been fount \n", validator.getName());
			
			return validator.getName();
		}
		
	}
	

	public static void main(String[] args) {
		
		String username = "test";
		String password = "test";
		UserValidator ldapValidator = new UserValidator("LDAP");
		UserValidator dbValidator = new UserValidator("DataBase");
		
		TaskValidator ldapTask = new TaskValidator(ldapValidator,username,password);
		TaskValidator dbTask = new TaskValidator(dbValidator,username,password);
		
		List<TaskValidator> taskList = new ArrayList<>();
		taskList.add(ldapTask);
		taskList.add(dbTask);
		
		ExecutorService executor = (ExecutorService)Executors.newCachedThreadPool();
		String result ;
		try{
			//只执行成功其中任何一个即可,会中断其他线程
			result = executor.invokeAny(taskList);
			System.out.printf("Main: Result : %s \n", result);
		}catch(InterruptedException e){
			e.printStackTrace();
		}catch(ExecutionException e){
			e.printStackTrace();
		}
		
		executor.shutdown();
		System.out.printf("Main: End of the Execution \n");
		
	}

}

 AbstractExecutorService.invokeAny()实现逻辑:

    /**
     * the main mechanics of invokeAny.
     */
    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)
            throw new NullPointerException();
        int ntasks = tasks.size();
        if (ntasks == 0)
            throw new IllegalArgumentException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        ExecutorCompletionService<T> ecs =
            new ExecutorCompletionService<T>(this);

        // For efficiency, especially in executors with limited
        // parallelism, check to see if previously submitted tasks are
        // done before submitting more of them. This interleaving
        // plus the exception mechanics account for messiness of main
        // loop.

        try {
            // Record exceptions so that if we fail to obtain any
            // result, we can throw the last exception we got.
            ExecutionException ee = null;
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            Iterator<? extends Callable<T>> it = tasks.iterator();

            // Start one task for sure; the rest incrementally
            futures.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;

            for (;;) {
                Future<T> f = ecs.poll();
                if (f == null) {
                    if (ntasks > 0) {
                        --ntasks;
                        futures.add(ecs.submit(it.next()));
                        ++active;
                    }
                    else if (active == 0)
                        break;
                    else if (timed) {
                        f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                        if (f == null)
                            throw new TimeoutException();
                        nanos = deadline - System.nanoTime();
                    }
                    else
                        f = ecs.take();
                }
                if (f != null) {
                    --active;
                    try {
                        return f.get();
                    } catch (ExecutionException eex) {
                        ee = eex;
                    } catch (RuntimeException rex) {
                        ee = new ExecutionException(rex);
                    }
                }
            }

            if (ee == null)
                ee = new ExecutionException();
            throw ee;

        } finally {
            for (int i = 0, size = futures.size(); i < size; i++)
                futures.get(i).cancel(true);
        }
    }
    /**
     * Executes the given tasks, returning the result
     * of one that has completed successfully (i.e., without throwing
     * an exception), if any do. Upon normal or exceptional return,
     * tasks that have not completed are cancelled.
     * The results of this method are undefined if the given
     * collection is modified while this operation is in progress.
     *
     * @param tasks the collection of tasks
     * @param <T> the type of the values returned from the tasks
     * @return the result returned by one of the tasks
     * @throws InterruptedException if interrupted while waiting
     * @throws NullPointerException if tasks or any element task
     *         subject to execution is {@code null}
     * @throws IllegalArgumentException if tasks is empty
     * @throws ExecutionException if no task successfully completes
     * @throws RejectedExecutionException if tasks cannot be scheduled
     *         for execution
     */
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

  方法说明:使用invokeAny()方法,当任意一个线程找到结果之后,立刻终结【中断】所有线程。

执行结果可能会有以下三种情况:

  • 任务都执行成功,使用过第一个任务返回的结果。
  • 任务都失败了,抛出Exception,invokeAny方法将抛出ExecutionException。
  • 部分任务失败了,会使用第一个成功的任务返回的结果。

玩具代码:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

//使用invokeAny()方法,当任意一个线程找到结果之后,立刻终结【中断】所有线程
public class UserValidator {
	
	private String name;
	public UserValidator(String name){
		this.name = name;
	}
	
	//Mock验证过程,有可能会抛出异常
	public boolean validate(String name ,String password){
		Random random = new Random();
		try{
			long duration = (long)(Math.random()*10);
			System.out.printf("Validator %s: Validating a user during %d seconds \n", this.name,duration);
			TimeUnit.SECONDS.sleep(duration);
		}catch(InterruptedException e){
			e.printStackTrace();
			return false;
		}
		return random.nextBoolean();
	}
	
	public String getName(){
		return name;
	}
	
	public static class TaskValidator implements Callable<String>{
		
		private UserValidator validator;
		private String name;
		private String password;
		
		public TaskValidator(UserValidator validator,String name,String password){
			this.validator = validator;
			this.name = name;
			this.password = password;
		}

		@Override
		public String call() throws Exception {
			
			if(!validator.validate(name, password)){
				System.out.printf("%s : The user has not been found \n", validator.getName());
				throw new Exception("Error validating user");
			}
			
			System.out.printf("%s: The user has been fount \n", validator.getName());
			
			return validator.getName();
		}
		
	}
	

	public static void main(String[] args) {
		
		String username = "test";
		String password = "test";
		UserValidator ldapValidator = new UserValidator("LDAP");
		UserValidator dbValidator = new UserValidator("DataBase");
		
		TaskValidator ldapTask = new TaskValidator(ldapValidator,username,password);
		TaskValidator dbTask = new TaskValidator(dbValidator,username,password);
		
		List<TaskValidator> taskList = new ArrayList<>();
		taskList.add(ldapTask);
		taskList.add(dbTask);
		
		ExecutorService executor = (ExecutorService)Executors.newCachedThreadPool();
		String result ;
		try{
			//只执行成功其中任何一个即可,会中断其他线程
			result = executor.invokeAny(taskList);
			System.out.printf("Main: Result : %s \n", result);
		}catch(InterruptedException e){
			e.printStackTrace();
		}catch(ExecutionException e){
			e.printStackTrace();
		}
		
		executor.shutdown();
		System.out.printf("Main: End of the Execution \n");
		
	}

}

 AbstractExecutorService.invokeAny()实现逻辑:

    /**
     * the main mechanics of invokeAny.
     */
    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
                              boolean timed, long nanos)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (tasks == null)
            throw new NullPointerException();
        int ntasks = tasks.size();
        if (ntasks == 0)
            throw new IllegalArgumentException();
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        ExecutorCompletionService<T> ecs =
            new ExecutorCompletionService<T>(this);

        // For efficiency, especially in executors with limited
        // parallelism, check to see if previously submitted tasks are
        // done before submitting more of them. This interleaving
        // plus the exception mechanics account for messiness of main
        // loop.

        try {
            // Record exceptions so that if we fail to obtain any
            // result, we can throw the last exception we got.
            ExecutionException ee = null;
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            Iterator<? extends Callable<T>> it = tasks.iterator();

            // Start one task for sure; the rest incrementally
            futures.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;

            for (;;) {
                Future<T> f = ecs.poll();
                if (f == null) {
                    if (ntasks > 0) {
                        --ntasks;
                        futures.add(ecs.submit(it.next()));
                        ++active;
                    }
                    else if (active == 0)
                        break;
                    else if (timed) {
                        f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
                        if (f == null)
                            throw new TimeoutException();
                        nanos = deadline - System.nanoTime();
                    }
                    else
                        f = ecs.take();
                }
                if (f != null) {
                    --active;
                    try {
                        return f.get();
                    } catch (ExecutionException eex) {
                        ee = eex;
                    } catch (RuntimeException rex) {
                        ee = new ExecutionException(rex);
                    }
                }
            }

            if (ee == null)
                ee = new ExecutionException();
            throw ee;

        } finally {
            for (int i = 0, size = futures.size(); i < size; i++)
                futures.get(i).cancel(true);
        }
    }

猜你喜欢

转载自woodding2008.iteye.com/blog/2326980