ExecutorService

An Executor that provides methods to manage termination and methods that can produce a Future for tracking progress of one or more asynchronous tasks.

An ExecutorService can be shut down, which will cause it to reject new tasks. Two different methods are provided for shutting down an ExecutorService. The shutdown() method will allow previously submitted tasks to execute before terminating, while the shutdownNow() method prevents waiting tasks from starting and attempts to stop currently executing tasks. Upon termination, an executor has no tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused ExecutorService should be shut down to allow reclamation of its resources.

Method submit extends base method execute(Runnable) by creating and returning a Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and then waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write customized variants of these methods.)

The Executors class provides factory methods for the executor services provided in this package.

Usage Examples

Here is a sketch of a network service in which threads in a thread pool service incoming requests. It uses the preconfigured newFixedThreadPool(int) factory method:

 classNetworkServiceimplementsRunnable{
   
privatefinalServerSocket serverSocket;
   
privatefinalExecutorService pool;

   
publicNetworkService(int port,int poolSize)
       
throwsIOException{
     serverSocket
=newServerSocket(port);
     pool
=Executors.newFixedThreadPool(poolSize);
   


   
publicvoid run(){// run the service
     
try{
       
for(;;){
         pool
.execute(newHandler(serverSocket.accept()));
       
}
     
}catch(IOException ex){
       pool
.shutdown();
     
}
   
}
 
}

 
classHandlerimplementsRunnable{
   
privatefinalSocket socket;
   
Handler(Socket socket){this.socket = socket;}
   
publicvoid run(){
     
// read and service request on socket
   
}
 
}}

The following method shuts down an ExecutorService in two phases, first by calling shutdown to reject incoming tasks, and then calling shutdownNow, if necessary, to cancel any lingering tasks:

 void shutdownAndAwaitTermination(ExecutorService pool){
   pool
.shutdown();// Disable new tasks from being submitted
   
try{
     
// Wait a while for existing tasks to terminate
     
if(!pool.awaitTermination(60,TimeUnit.SECONDS)){
       pool
.shutdownNow();// Cancel currently executing tasks
       
// Wait a while for tasks to respond to being cancelled
       
if(!pool.awaitTermination(60,TimeUnit.SECONDS))
           
System.err.println("Pool did not terminate");
     

   
}catch(InterruptedException ie){
     
// (Re-)Cancel if current thread also interrupted
     pool
.shutdownNow();
     
// Preserve interrupt status
     
Thread.currentThread().interrupt();
   
}
 
}}

Memory consistency effects: Actions in a thread prior to the submission of a Runnable or Callable task to an ExecutorService happen-before any actions taken by that task, which in turn happen-before the result is retrieved via Future.get().

An asynchronous process is a process which has the probability to not finishing its execution right away, but later. If the execution finishes right away, then those are known as synchronous process. Special care is needed when designing asynchronous process, because we are used to synchronous programming model.

The java.util.concurrent.ExecutorService interface represents an asynchronous execution mechanism which is capable of executing tasks in the background. It extends Executor interface.

Implementation of Executor service
Here are the type of thread pools you can create with the Executors class, which are got from the factory class called Executors. Following are the implementation of ExecutorService :
Single Thread Executor : A thread pool with only one thread. So all the submitted task will be executed sequentially.
Method : Executors.newSingleThreadExecutor()
Cached Thread Pool : A thread pool that create as many threads it needs to execute the task in parralel. The old available threads will be reused for the new tasks. If a thread is not used during 60 seconds, it will be terminated and removed from the pool.
Method : Executors.newCachedThreadPool()
Fixed Thread Pool : A thread pool with a fixed number of threads. If a thread is not available for the task, the task is put in queue waiting for an other task to ends.
Method : Executors.newFixedThreadPool()
Scheduled Thread Pool : A thread pool made to schedule future task.
Method : Executors.newScheduledThreadPool()
Single Thread Scheduled Pool : A thread pool with only one thread to schedule future task.
Method : Executors.newSingleThreadScheduledExecutor()

So we can create our ExecutorService like this:

ExecutorService executorService1 = Executors.newSingleThreadExecutor();
ExecutorService executorService2 = Executors.newFixedThreadPool(4);
ExecutorService executorService3 = Executors.newScheduledThreadPool(4);


Methods in Executor Service
There are a few different ways to delegate tasks for execution to an ExecutorService:

  • execute(Runnable) - The execute(Runnable) method takes a java.lang.Runnable object, and executes it asynchronously.There is no way of obtaining the result of the executed Runnable.
  • submit(Runnable) - The submit(Runnable) method also takes a Runnable implementation, but returns a Future object. This Future object can be used to check if the Runnable as finished executing.
  • submit(Callable)-The submit(Callable) method is similar to the submit(Runnable) method except for the type of parameter it takes. The Callable instance is very similar to a Runnable except that its call() method can return a result. The Runnable.run() method cannot return a result.
  • invokeAny(...) - The invokeAny() method takes a collection of Callable objects, or subinterfaces of Callable. Invoking this method does not return a Future, but returns the result of one of the Callable objects. You have no guarantee about which of the Callable's results you get. Just one of the ones that finish.
  • invokeAll(...) - The invokeAny() method takes a collection of Callable objects, or subinterfaces of Callable. Invoking this method does not return a Future, but returns the result of one of the Callable objects. You have no guarantee about which of the Callable's results you get. Just one of the ones that finish.


Lets look at them one by one. First get the instance of executor service:

ExecutorService executorService = Executors.newSingleThreadExecutor();


execute()
Example to be added soon.
submit()
submit() takes callable and returns Future object.

Callable c = new Callable() {
     public Object call() throws Exception {
         Thread.sleep(3000);
          ReturnObject rt =  new ReturnObject();
          rt.setReturnName(“serkan sunel”);
          return rt;
      }
  };

  Future future = executorService.submit(c);
//Now get the result 
  try {
       Object returnObj = future.get();
       System.out.println(“returned :+ returnObj);
  } catch (Exception e) {
       e.printStackTrace(); 
  }


So we can get result of the thread.

Closing the ExecutorService
You can close the executor service by calling shutdown() method. But this will not shut down immediately, but it will no longer accept new tasks, and once all threads have finished current tasks, the ExecutorService shuts down. All tasks submitted to the ExecutorService before shutdown() is called, are executed. You can use shutdownNow() to shutdown the service immediately.

Example
We are going to look into a program, which will initialize a fixed pool size ExecutorService and submit number of tasks (threads) to the executor service to execute them. To simulate asynchronous behavior each of those threads will work, and the sleep for a while, and then again work before returning result.

public class ExecutorServiceWithCallable {

public void executorServiceForCallable(int poolSize) throws 
                                   ExecutionException, InterruptedException {

        ExecutorService executorService = Executors.newFixedThreadPool(poolSize);

        List<Future> futures = new ArrayList<Future>();
        for (int index = 0; index < poolSize; index++) {
            Future future = executorService.submit(new RepeatingGreetings(index));
            futures.add(future);
        }

        for (Future future : futures) {
            System.out.println(future.get());
        }
}
class RepeatingGreetings implements Callable {
        private int index;

        RepeatingGreetings(int index) {
            this.index = index;
        }

        @Override
        public V call() throws Exception {
            System.out.println("Callable: " + index + " is working");
            int sleepValue = (int) (Math.random() * 1000);
            Thread.sleep(sleepValue);
            return (V) ("Callable: " + index + " sleept for: " + sleepValue);
        }
    }
}


First we are going to talk about the Callable we are creating, and then we will look into ExecutorService.

Callable is same as java.lang.Runnable, both of them are designed to be executed by another thread. The only difference is, Callable is designed to return result, but Runnable are not. The call() method of Callable works same as run() method of Runnable.

The use of Callable on our example is pretty straight forward. The RepeatingGreetings is Callable which will print a message, sleep for a random amount of time, and then return a string message as result of execution.

The ExecutorServiceWithCallable is doing the main job here. We are creating a new executor service for supplied pool size. Then we are submitting our Callables to the ExecutorService to execute. As soon as we invoke the submit() method of ExecutorService the Callable are handed over to ExecutorService to execute. Here one thing we have to note, the submit() is not blocking. So, all of our Callables will be submitted right away to the ExecutorService, and ExecutorService will decide when to execute which callable. For each Callable we get a Future object to get the result later.

Once the Callables are submitted for execution, we are iterating through all Futures to get the result of execution. We are invoking the get() method of Future to get the result. Here we have to remember that, the get() is a blocking method. So the first invocation of get() will wait until that Callable is finished. Once we receive the result of the execution of first Callable it will wait for next Callable to finish, and so on. Since the get() is blocking, we could put the iteration on a separate thread to continue the execution, and get the result later when all Futures are ready with their results.

There is also, another useful method named isDone() on Future which let us check if the Callable for that Future is finished or not.

Output
The two random execution of our above example for five Callables produces output like

Callable: 0 is working
Callable: 1 is working
Callable: 3 is working
Callable: 2 is working
Callable: 4 is working
Callable: 4 sleept for: 18
Callable: 0 sleept for: 70
Callable: 1 sleept for: 449
Callable: 3 sleept for: 744
Callable: 2 sleept for: 844

Another Random output -

Callable: 0 is working
Callable: 1 is working
Callable: 3 is working
Callable: 2 is working
Callable: 4 is working
Callable: 0 sleept for: 270
Callable: 1 sleept for: 348
Callable: 2 sleept for: 427
Callable: 4 sleept for: 428
Callable: 3 sleept for: 564

转载于:https://www.cnblogs.com/qiengo/archive/2013/03/23/2976692.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值