Implementation of threads in Java

  1. inheritanceThreadClass, rewriterun()Method, and then through the callstart()Start a thread and execute ourrun()Methods.
  2. implementationRunnableOf the interfacerun()Method, and then throughThreadThe constructor ofRunnableInterface, balabala…

Both methods are based on the template model, and the user does not care how to apply for a thread to the operating system, but only what logic is executed in the thread that is opened. But we all know that the Runnable interface looks like this

@FunctionalInterface
public interface Runnable {
    public abstract void run(a);
}
Copy the code

There is no return value. However, in some scenarios, we need to start the thread to execute a piece of logic and then get the return value. In this case, we need the Callable interface.

Let’s take a chestnut that uses Callable, just to show you what I’m usingCallableInterface, I’m not using java8’s functional simplification here.

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        RunnableFuture<String> runnableFuture = new FutureTask<>(new Callable<String>() {
            @Override
            public String call(a) throws Exception {
                return "HelloCallable"; }});new Thread(runnableFuture).start();
        String s = runnableFuture.get();
        System.out.println(s);
    }
Copy the code

We write the logic we need to execute in the Call method, wrap the interface with FutureTask, and finally submit the runnableFuture to Thread, at which point we can get the return value via runnableFuture.get.

The principle of

  1. The class diagram for FutureTask is shown below

  1. The Future interface contains methods to get the result of the returned valuegetIf the thread does not complete the task, calling this method blocks the current thread and cancels the taskcancelTo check whether the task is completeisDoneAnd whether the mission was canceledisCancelled.
public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled(a);

    boolean isDone(a);

    V get(a) throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
Copy the code
  1. The RunnableFuture interface is equivalent to the integration and Future and Runnable interfaces, without adding additional functionality.
public interface RunnableFuture<V> extends Runnable.Future<V> {
   
    void run(a);
}
Copy the code

FutureTask has two key attributes: the Callable interface and the outcome attribute that stores the return value of the Call method.

public class FutureTask<V> implements RunnableFuture<V> {

    private Callable<V> callable;

    private Object outcome; // non-volatile, protected by state reads/writes. }Copy the code

The code for the run method in FutureTask is as follows:

    public void run(a) {
        if(state ! = NEW || ! UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if(c ! =null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if(ran) set(result); }}finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if(s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); }}Copy the code

The run method executes Callable’s call method and assigns the return value to the member variable. If an exception occurs, enter the catch block and call the setException method, which looks like this:

    protected void setException(Throwable t) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = t;
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final statefinishCompletion(); }}Copy the code

The exception object is assigned to the outcome, so if the call method is executed successfully, the return value is saved in the outcome, and if it fails, the exception object is saved in the outcome.

Then, get the return value through the get method, the specific logic of get method is as follows:

    public V get(a) throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false.0L);
        return report(s);
    }
    private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }
Copy the code

The get method will determine the status of the Callable task. If it is not completed, it will block the current thread and wait for completion. If it is canceled, it will throw an exception. If it is the result of execution, return it directly.


FutureTask interface implementation is more complex, it is relatively difficult to read the source code to understand, but in essence, FutureTask interface is a producer consumer model, if producers do not finish production, so will block the consumer, the consumer into a blocking queue, producer after the production, will wake blocking consumers to spend as a result, That’s how it works. Here’s a simplified version of the implementation.

class MyRunnableFuture<T> implements RunnableFuture<T> {

    private Callable<String> callable;

    private Object returnObj;

    private ReentrantLock lock = new ReentrantLock();

    private Condition getCondition = lock.newCondition();

    public MyRunnableFuture(Callable<String> callable) {
        this.callable = callable;
    }

    @SneakyThrows
    @Override
    public void run(a) {
        this.returnObj = this.callable.call();
        try {
            lock.lock();
            this.getCondition.signalAll();
        } finally{ lock.unlock(); }}@Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        throw new NotImplementedException();
    }

    @Override
    public boolean isCancelled(a) {
        throw new NotImplementedException();
    }

    @Override
    public boolean isDone(a) {
        throw new NotImplementedException();
    }

    @Override
    public T get(a) throws InterruptedException, ExecutionException {
        if (returnObj == null) {
            try {
                lock.lock();
                this.getCondition.await();
            } finally{ lock.unlock(); }}return (T) returnObj;
    }

    @Override
    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        throw newNotImplementedException(); }}Copy the code