jdk8 source code: concurrent package

Here's an analysis of some of the classes under the concurrent package! ! !


1.Executor/ExecutorService

        Thread resources are more important, in order to reuse the threads that have been created and reduce the performance overhead when creating and destroying threads. Because creating and managing threads is exhausting, and the operating system usually has a limit on the number of threads, it is recommended to use a thread pool to execute tasks concurrently, rather than creating a thread each time a request comes in.

        Executor: Separating the task itself and the execution of the task (Thread, instead, softens everything together, which is very difficult to manage). Used to dispatch Runnables and Callables.

        ExecutorService: Extends Excetor and provides Future asynchronous support (check if Future has a result when needed after the task is submitted, its get() method is blocking, if the task has not been completed when it is called, it will wait until the end of the task execution) .

        The interface source code is as follows:

// top level interface
public interface Executor {
    // execute the task
    void execute(Runnable command);
}
//Thread pool interface
public interface ExecutorService extends Executor {
	//Close the thread pool, no longer accept new tasks, wait for all tasks to complete
    void shutdown();
    //Close the thread pool, no longer accept new tasks, and return to the list of tasks waiting to be executed
    List<Runnable> shutdownNow();
    //Whether the thread pool is closed
    boolean isShutdown();
    //The thread pool is closed and returns true if all tasks are completed
    boolean isTerminated();
    //Block until all threads are executed or time out
    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
    //Submit a task and give it to the thread pool for execution (callable has its own return result)
    <T> Future<T> submit(Callable<T> task);
    //Submit a task and give it to the thread pool for execution (runnable does not have its own return result, which is represented by result)
    <T> Future<T> submit(Runnable task, T result);
    //Submit a task to the thread pool for execution, and return the future of the task
    Future<?> submit(Runnable task);
    //Execute the given task set (timeout time can be specified), all complete (no exception is thrown), return the future set
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
    //Execute the given task (timeout time can be specified), complete (no exception is thrown), return future
    <T> T invokeAny(Collection<? extends Callable<T>> tasks)  throws InterruptedException, ExecutionException;
    <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

2.AbstractExecutorService

        First, take a brief look at the task-related interfaces and implementation classes.

        Future interface: used to implement asynchronous tasks to obtain task results. Callable tasks return Future objects. The source code is as follows:

public interface Future<V> {
	// try to cancel the task
    boolean cancel(boolean mayInterruptIfRunning);
    //Return true if the task was canceled before it completed normally
    boolean isCancelled();
    //If the task is complete, return true
    boolean isDone();
    //Query result (block until the task returns the result)
    V get() throws InterruptedException, ExecutionException;
    //Query result (block until the specified time)
    V get(long timeout, TimeUnit unit)throws InterruptedException, ExecutionException, TimeoutException;
}

        Runnable interface: used to create tasks. The source code is as follows:

public interface Runnable {
    //task executor
    public abstract void run();
}

        RunnableFuture interface: a sub-interface of Future and Runnable. Task creation, asynchronous support. The source code is as follows:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    //task executor
    void run();
}

        FutureTask class: The interface implementation class of RunnableFuture. It is an asynchronous task executor that supports cancellation and supports the execution of Callable or Runnable type tasks. The source code is subsequently analyzed separately.

        AbstractExecutorService gives an abstract implementation of ExecutorService. For asynchronous tasks, scheduling management of task execution, etc. Analyze related methods in turn.

        Create a task, use the task to construct a FutureTask and return it, the source code is as follows:

	//create task
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    	//The value in the constructor is used to save the return result of the task
        return new FutureTask<T>(runnable, value);
    }
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
    

        To submit a task is to call execute(), pass in the task for execution, and hand it over to the subclass for implementation. The source code is as follows:

    //Submit the task
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        //The abstract class does not implement execute(), which is handed over to the subclass for implementation
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

        Execute the given task set and return the result of a task that has been successfully completed (the task gets the result and no exception is thrown as the execution is successful). The source code is as follows:

    //Execute the task set and return the first successful result
    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();
        //Construct the futures collection
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
        //ExecutorCompletionService can use the blocking queue to save the execution results of multiple threads (future type)
        ExecutorCompletionService<T> ecs = new ExecutorCompletionService<T>(this);
        try {

            ExecutionException ee = null;
            // nanos representation of timeout
            final long deadline = timed? System.nanoTime () + nanos: 0L;
            Iterator<? extends Callable<T>> it = tasks.iterator();
            //ExecutorCompletionService submits the task and returns the future, and then adds it to the collection
            futures.add(ecs.submit(it.next()));
            --ntasks;
            int active = 1;
            for (;;) {
            	// Poll the completed tasks in the queue, pop its future and delete it from the queue
                Future<T> f = ecs.poll();
                //future is empty, call the take of the blocking queue to get the execution result of the corresponding thread
                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();
                }
                //future is not empty, get its result
                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);
        }
    }


    //Execute the task collection and return the result of a successful task (supports timeout)
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
    	// doInvokeAny ()
        return doInvokeAny(tasks, true, unit.toNanos(timeout));
    }
    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
            throws InterruptedException, ExecutionException {
            try {
            	// doInvokeAny ()
                return doInvokeAny(tasks, false, 0);
            } catch (TimeoutException cannotHappen) {
                assert false;
                return null;
            }
        }

        Execute the given task, all tasks successfully completed() return their future collection. The source code is as follows:

    //Execute the task collection and return the Future collection of the task (supports timeout)
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
        throws InterruptedException {
        if (tasks == null)
            throw new NullPointerException();
        long nanos = unit.toNanos(timeout);
        //Construct the future collection
        ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
        boolean done = false;
        try {
            for (Callable<T> t : tasks)
            	//newTaskFor() converts the Callable type to the FutureTask type and adds it to the futures collection
                futures.add(newTaskFor(t));
            final long deadline = System.nanoTime () + nanos;
            final int size = futures.size();
            // execute all tasks
            for (int i = 0; i < size; i++) {
            	//call execute() here
                execute((Runnable)futures.get(i));
                nanos = deadline - System.nanoTime ();
                if (nanos <= 0L)
                    return futures;
            }
            //Call the get of all futures, blocking to get the task result
            for (int i = 0; i < size; i++) {
                Future<T> f = futures.get(i);
                if (!f.isDone()) {
                    if (nanos <= 0L)
                        return futures;
                    try {
                    	//FutureTask calls get to get the task result
                        f.get(nanos, TimeUnit.NANOSECONDS);
                    } catch (CancellationException ignore) {
                    } catch (ExecutionException ignore) {
                    } catch (TimeoutException toe) {
                        return futures;
                    }
                    nanos = deadline - System.nanoTime ();
                }
            }
            done = true;
            return futures;
        } finally {
            if (!done)
                for (int i = 0, size = futures.size(); i < size; i++)
                    futures.get(i).cancel(true);
        }
    }
    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
            throws InterruptedException {
            if (tasks == null)
                throw new NullPointerException();
            ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
            boolean done = false;
            try {
                for (Callable<T> t : tasks) {
                    RunnableFuture<T> f = newTaskFor(t);
                    futures.add(f);
                    execute(f);
                }
                for (int i = 0, size = futures.size(); i < size; i++) {
                    Future<T> f = futures.get(i);
                    if (!f.isDone()) {
                        try {
                            f.get();
                        } catch (CancellationException ignore) {
                        } catch (ExecutionException ignore) {
                        }
                    }
                }
                done = true;
                return futures;
            } finally {
                if (!done)
                    for (int i = 0, size = futures.size(); i < size; i++)
                        futures.get(i).cancel(true);
            }
        }
}

3.ThreadPoolExecutor

A general thread pool consists of three parts: scheduler, thread queue, and task queue. The scheduler assigns the tasks in the task queue to the threads in the thread queue for execution, and after the execution is completed, the thread will go to the thread queue again.

ThreadPoolExecutor is a direct subclass of AbstractExecutorService. Provides the most basic thread pool function. ThreadPoolExecutor does not have a scheduler, and all threads in the thread queue automatically acquire tasks in the task queue for execution. It can be seen that the core is actually to automatically control the length of the thread queue to match the length of the task queue, so that the tasks can be executed reasonably in order. The thread queue stores threads or idle threads currently processing tasks, and the task queue stores tasks to be executed (tasks being executed by threads are not in the task queue).

Use corePoolSize (reasonable capacity) and maximumPoolSize (maximum capacity) to control the length of the thread queue. Whenever execute(Runnable) is called to submit a new task to the thread pool, the number of threads will be automatically adjusted, that is, if a new task comes, the thread will grow first. When the number reaches a reasonable number, new tasks will be added to the task queue first. If the task queue cannot be placed, the number of threads will increase to the maximum number. As follows:
If the reasonable capacity has not been exceeded: a new thread is required to process the new task.
If it exceeds the most reasonable capacity and is less than the maximum capacity: the new task will be placed in the task queue if the task queue is not full, and a new thread will be created to process the new task if the task queue is full. If the task
is equal to the maximum capacity: if the task queue is not full, the new task will be placed in the task queue, and if the task queue is full, the rejection policy (RejectedExecutionHandler) will be executed.




Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325448554&siteId=291194637