Tutorials Hut

Java Concurrency Package And Useful Features: Executor, executorService and Thread pool

Java concurrency package provides a lot of useful classes and methods to achieve effective multi-threading and also build in solutions to overcome common concurrency problems for example deadlock etc. Let’s look into Executor, ExecutorService and Thread pools in java.

Executor

Executor is an interface which has an execute method; the executor implementation class needs to override it and provide an implementation to run a passed Runnable thread object.

Example:

package threads;

import java.util.concurrent.Executor;
public class ExecutorExamples {

public static void main(String[] args) {
    MyTask t1 = new MyTask();
    MyExecutor executor = new MyExecutor();
    executor.execute(t1);
}
}

class MyExecutor implements Executor {
@Override
public void execute(Runnable command) {
  command.run();
}
}

class MyTask implements Runnable {
@Override
public void run() {
  System.out.println("Hello I am a thread called from Executor, i believe.");
}
}

Output

Hello I am a thread called from Executor, i believe.

ExecutorService

ExecutorSerice is an interface which provides details of different thread pool implementations, by using the Executors class we can create instances of different thread pool ExecutorService instances. See below example.

By using executor service we can easily manage a pool of threads, submit them for execution, check and terminate them as well.

ExecutorService Example with different thread pools

package threads;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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

    //Different executor service with diff thread pool options
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
     ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);

    AotherThread t1 = new AotherThread();
     AotherThread t2= new AotherThread();

    singleThreadExecutor.submit(t1);
    singleThreadExecutor.submit(t2);

//Kills all the thread immediately
//executorService.shutdownNow();

    //Allows threads to complete
//executorService.shutdown();

}
}

class AotherThread implements Runnable {
@Override
public void run() {
    System.out.println("Thread job using lambda");
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

Output

Thread job using lambda
Thread job using lambda

Methods In ExecutorService

submit() – It is used to submit the thread/task.

shutdownNow() – It is used to kill all threads immideately.

Shutdown() – It is used to kill all thread within the service.

isTerminated() – Checks if it is terminated

ScheduledExecutorService

ScheduledExecutorService is similar to ExecutorService which manages threads in pool and executes them, but in addition to this we can provide time in this service which will indicate when to start or execute the service.

Example:

executorService.scheduleAtFixedRate(() -> {
// ...
}, 1, 10, TimeUnit.SECONDS);

executorService.scheduleWithFixedDelay(() -> {
// ...
}, 1, 10, TimeUnit.SECONDS);

Future In Java Using Callable Interface and Managing It with ExecutorService thread pool pools

Example

package threads;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ExecutorWithCallable {
public static void main(String[] args) throws Exception {

    //Different executpr service with diff thread pool options
     ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2);

    CallableThread t0 = new CallableThread();
    Future<Callable> fs = fixedThreadPool.submit(t0);
     System.out.println(fs.get());

    ArrayList<Callable> myCallableThreadsList = new ArrayList<Callable>();
    CallableThread t1 = new CallableThread();
     CallableThread t2 = new CallableThread();

    myCallableThreadsList.add(t1);
     myCallableThreadsList.add(t2);

    List<Future> resultsFuture = fixedThreadPool.invokeAll(myCallableThreadsList);
    for(Future fStr: resultsFuture) {
           System.out.println(fStr.get());
    }
}
}

class CallableThread implements Callable {
@Override
public String call() throws Exception {
    System.out.println("Thread job using lambda, name of thread:"+Thread.currentThread().getName());
    return "done";
}
}

Output

Thread job using lambda, name of thread:pool-1-thread-1
done
Thread job using lambda, name of thread:pool-1-thread-2
Thread job using lambda, name of thread:pool-1-thread-1
done
done

Reference

Next Articles

  • Java Concurrency Package And Useful Features: CountDownLatch, CyclicBarrier, Semaphore and Mutex

















  • Leave a Reply

    Your email address will not be published. Required fields are marked *