Introduction to the

This article is the beginning of Java multithreading, this article mainly simple talk about the thread state, several ways to create, and then from the source point of view to analyze the next FutureTask, FutureTask class and Callable, and Runnable associated. And it implements the Future interface, which can manage our Callable or Runnable well.

thread

Let’s talk briefly about threads: a thread is the smallest unit an operating system can schedule. It is contained and executed in a process. A process can contain multiple threads, each performing a different task.

Several states of a thread

 public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }
Copy the code
  1. Initial state New: The initial state of thread creation is when we create a New thread before it starts
  2. Runnable: when the thread calls the Start method, the thread becomes ready and waits for the CPU to allocate an executable time slice. If the time slice is allocated, the thread becomes running. Runnable is a generic term for ready and runnding.
  3. Blocked: This state is entered into a Synchronized method or block of code, at which point the thread has to wait to acquire a Monitor Lock object. By the way, each of our objects has a corresponding Monitor associated with it in the JVM. We all know that Synchronized is implemented through monitorEnter and Monitorexit. When the JVM executes monitorEnter, it retrieves the monitor associated with the current object, and the current monitor becomes locked. Later threads will have to wait for the Monitor object when they reach this point, and the thread state becomes blocked
  4. Waiting: a thread is Waiting for a wakeup signal when it encounters Object#wait,LockSupport#park, or Thread#join.
  5. Time-waiting: this is a finite wait. Each of the methods I listed above has a Waiting method with a Waiting Time. The state of the thread executing this method is time-waiting
  6. Termination state The state of the Terminated thread after execution is complete

Several threads are created

Some people say there are three ways to create something and some people say there are two. See the oracle’s website Actually said That is two ways to create: docs.oracle.com/en/java/jav…

Directly inherits the Thread interface

This is the first way to directly inherit the Thread interface

class MyThread extends Thread {

    public MyThread(a) {
        this.setName("MyThread");
    }

    @Override
    public void run(a) {
        System.out.printf("【%s】 is runing", Thread.currentThread().getName());
        super.run();
    }

    public static void main(String[] args) {
        MyThread myThread=newMyThread(); myThread.start(); }}Copy the code

Runnable

<! --Runnable.java-->public interface Runnable {
    public abstract void run(a);
   }

   public static void main(String[] args) {

       Runnable runnable=new Runnable() {
           @Override
           public void run(a) {
               System.out.printf("【%s】 is runing", Thread.currentThread().getName()); }}; Thread runnableThread=new Thread(runnable);
        runnableThread.start();
    }
Copy the code

Callable

In fact, this way and the above kind is essentially the same, why would you say so?

Callable is used in conjunction with the Future interface, which is how we normally use it

<! --Callable.java-->public interface Callable<V> {
          V call(a) throws Exception;
      }

       Callable<String> callable = new Callable<String>() {
            @Override
            public String call(a) throws Exception {
                return Thread.currentThread().getName() + "---burgxun"; }}; FutureTask<String> futureTask =new FutureTask(callable);
        Thread callableThread = new Thread(futureTask);
        callableThread.start();

        String msg = futureTask.get();
        System.out.println(msg);
Copy the code

FutureTask

FutureTask takes a look at the inheritance structure of this class

public class FutureTask<V> implements RunnableFuture<V> {}
public interface RunnableFuture<V> extends Runnable.Future<V>{}
Copy the code

FutureTask essentially implements the Runnable and Future interfaces so we can pass in the FutureTask object when new Thread(), and the Future interface we know is used to get the results of Callable execution, So we can use the FutureTask#get method to get the result of the Callable

FutureTask is a class that manages tasks. There are two tasks, a Callable with a return value and a Runable with no return value. Look at its constructor

    /** This is the Callable */ that FutureTask will execute
    private Callable<V> callable;
    /** this is where we store the results of the run and the value we get with get is the */ from the outcome side
    private Object outcome; // non-volatile, protected by state reads/writes
    /** The thread running FutureTask */
    private volatile Thread runner;
   
   public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
  
   public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
Copy the code

First we see that FutureTask has two constructors one callable and one runnable, * If the callable variable in FutureTask is used to store the task to be executed by the Executors, pay attention to the following place: * If the callable(runnable, result) is used by the Executors. A tool class for task execution, we look at the code in detail:

<! --Executors.java-->public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return newRunnableAdapter<T>(task, result); } <! --RunnableAdapter is Executors interior class -->static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call(a) {
            task.run();
            returnresult; }}Copy the code

RunnableAdapter is a Runnable adapter that converts a Runnable to a Callable constructor called result, which we normally don’t use. We just pass null.

Future

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

If we look at the methods defined by the Future interface, we can see that the Get method has a Get method for waiting to block, two methods for determining the status of the task, and a method for canceling the task. FutureTask inherits RunnableFuture, RunnableFuture implements the Future, and FutureTask indirectly implements the Future interface.

The Get method

Let’s see how our get method for getting the value of a Callable run is implemented in FutureTask

    private volatile int state;
    private static final int NEW          = 0;//
    private static final int COMPLETING   = 1;// In progress
    private static final int NORMAL       = 2;// Task completed status
    private static final int EXCEPTIONAL  = 3;// Task execution is abnormal
    private static final int CANCELLED    = 4;// Task cancelled
    private static final int INTERRUPTING = 5;// The task is interrupted
    private static final int INTERRUPTED  = 6;// The task is interrupted

    / * * *@throws CancellationException {@inheritDoc} * /
    public V get(a) throws InterruptedException, ExecutionException {
        int s = state;//state is the task status
        if (s <= COMPLETING)// Well, the state value of those years is only new, well
            s = awaitDone(false.0L);// Join the wait is an infinite wait
        return report(s);
    }
    
     private V report(int s) throws ExecutionException {
        Object x = outcome;
        if (s == NORMAL)//NORMAL Indicates that the task is executed. The outcome value is obtained from the outcome field
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw newExecutionException((Throwable)x); } <! Add the thread that fetched the value to the waiting list -->private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;// Timed is false and the value is 0
        WaitNode q = null;// Waiting node is an inner class
        boolean queued = false;
        for (;;) {// Spin waitNode<! In order to respond to the interrupt status, the thread is used to detect the interrupt status.if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state;// The status of the current task
            if (s > COMPLETING) {// If the task status is greater than 1, then the task is completed and exits the loop
                if(q ! =null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING) // If the task is still executing, yield is invoked to yield the currently allocated CPU slice, recompeting
                Thread.yield();
            else if (q == null)// The state of s over here should be 0, i.e., the new state
                q = new WaitNode();
            else if(! queued) <! - use the CAS will be the current waitNode node into the rear of the waiters Will be performed for the first time - > queued pareAndSwapObject (= UNSAFE.comthis, waitersOffset,
                                                     q.next = waiters, q);
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            else
                LockSupport.park(this);// If the thread with no deadline is blocked, the thread is in a state of waiting, waiting to wake up after the task has completed}}Copy the code

After looking at the process above, we know how we get the value using the GET method, which is actually obtained from the outcome field in FutureTask. The get method is called get, but it will block the thread if the task is not completed and the return value cannot be retrieved.

Run method

The Get method tells us that the outcome is worth getting from the outcome. How does the outcome Get from the outcome? Let’s see what the run method does

    public void run(a) {<! Determine whether the current task status is correct or notnew, the task has been started directly return; If CAS fails to set the thread of execution for the current task, it also returns ~-->if(state ! = NEW || ! UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if(c ! =null && state == NEW) {// The task state must be the initial state New
                V result;
                boolean ran;// Check whether the task is completed
                try {
                    result = c.call();// The main logic to execute the task
                    ran = true;// The execution is complete
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);// Set the Result value if the task is completed}}}protected void set(V v) {
        // Change the execution state of the current FutureTask. It's weird that the state has been changed. It's executing instead of NORMAL
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // This changes the state of the task. NORMAL is the final state of the task
            finishCompletion();// After the task is complete, the action to be performed should be to wake up the blocked thread to fetch the value}}/** * Post and signal all waiting threads, invokes done(), and * nulls out callable. Execute the done() method and set FutureTask's callable to NULL */
    private void finishCompletion(a) {
        // assert state > COMPLETING;
        for(WaitNode q; (q = waiters) ! =null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if(t ! =null) {
                        q.thread = null;
                        LockSupport.unpark(t);// Wake up the waiting node} <! -- This is a normal list. Removing a node is a one-way list --> WaitNode next = q.next;if (next == null)
                        break;
                    q.next = null; // Unlink to help GC set null to disconnect the current node from the list and help GC to reclaim the current node
                    q = next;// 
                }
                break;
            }
        }
        done();// is an empty method that can be subclassed
        callable = null;        // The current task completes directly with the task body set to null
    }
Copy the code

How to assign the outCome, wake up the waiting blocked thread, and finally get the value through GET

conclusion

This article will help you understand what FutureTask does, how it relates to Runnable and Callable, and how Callable gets results from execution.