併發編程線程基礎(一)---線程的建立

建立線程的幾種方式:java

 1. 經過繼承 Thread 類ide

 public static class MyThreadOne extends Thread{
        @Override
        public void run() {
            System.out.println("MyThreadOne running ... ");
        }
    }

2. 經過實現Runnable接口this

 public static class MyThreadTwo implements Runnable{
        @Override
        public void run() {
            System.out.println("myThreadTwo running ... ");
        }
    }

3. 經過Callable接口和FutureTask實現有返回值的線程spa

 public static class MyThreadThree implements Callable<String>{

        @Override
        public String call() throws Exception {
            System.out.println("MyThreadThree running .... ");
            return "success";
        }
}

 

具體的線程執行線程

 public static void main(String[] args) {
        MyThreadOne myThreadOne  = new MyThreadOne();
        myThreadOne.start();

        Thread thread = new Thread(new MyThreadTwo());
        thread.start();


        // futureTask 類實現了  RunnableFuture 接口 該接口繼承了 Runable 接口  繼承runnable 接口 就能經過  new Thread(new Runable())方式
        // 經過線程執行  futureTask 中的 run 方法 ; 繼承 future 接口 能經過 get 方法 阻塞線程 獲取放回直
        FutureTask<String> stringFutureTask = new FutureTask<>(new MyThreadThree());


        new Thread(stringFutureTask).start();

        try {
            // get 時經過  LockSupport.park()  阻塞線程
            String s = stringFutureTask.get();
            System.out.println(s);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

}

 

原理探究:debug

 

1. 關於第三種方式是如何實現線程執行 實現 Callable 接口中的 call 方法的?blog

 經過debug 一步一步查看執行過程能夠發現繼承

 thread.start方法建立線程,當線程被CPU分配時間片時, Runable實現類中的 run 方法,由於  FutureTask 類實現了 RunnableFuture 接口 該接口繼承了 Runnable 和  Future接口接口

實際上執行的是FutureTask  中的 run 方法,run 方法中執行  Callable接口中run 方法 也就是 本身實現類中的run 方法;rem

執行流程:

FutureTask<String> stringFutureTask = new FutureTask<>(new MyThreadThree());
new Thread(stringFutureTask).start();

 

線程啓動:

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

當線程分配CPU 時間後執行 run 方法:

/* What will be run. */
private Runnable target;

public void run() { if (target != null) { target.run(); } }

 

RunableFuture 繼承 Runnable 接口 和 Future 接口 ,而 FutureTask s實現 Runnable接口,執行 FutureTask 中的 run 方法

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

    public void run() {
        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 {
            // 執行 Callale 實現類中的 call方法 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); } } }

 該方法會調用 Callable 的接口的實現類,也就是咱們本身的Callable 接口實現類中的call方法

 

2. get方法是如何獲取到 線程的返回值的?

 

能夠發如今執行FutureTask 中的 run 方法中,在執行Callable 的call 放回 會獲取到 返回值 放到 FutureTask 的局部變量 outcoome 中,而後在經過 get方法當線程執行完成時,獲取該臨時變量的值返回;

 

執行 run 方法,執行完成後執行set 方法

    public void run() {
        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);
        }
    }

  

 set方法將方法的返回值放到 全局變量outcome 中

    protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }

 

當執行get方法時

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

 當線程執行完成 會執行report 方法 從裏面拿到返回值

    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);
    }

  

3. get方法爲啥會阻塞線程?

執行get方法時候,會判斷線程的狀態,若call方法還未執行完成,會執行 awaiter方法,該方法會經過循環判斷線程狀態,若線程狀態被中斷,則經過異常放回

若線程執行完成,則結束循環返回,若爲其餘狀態,經過 LockSupport.park()加鎖

 

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

 

執行awaitNode

 private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state;
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            else if (q == null)
                q = new WaitNode();
            else if (!queued)
                queued = UNSAFE.compareAndSwapObject(this, 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);
        }
    }

  

 

 萬事預則立,不預則廢~~~加油

相關文章
相關標籤/搜索