码迷,mamicode.com
首页 > 编程语言 > 详细

并发编程线程基础(一)---线程的创建

时间:2020-08-25 15:54:12      阅读:48      评论:0      收藏:0      [点我收藏+]

标签:ssi   thread   sof   zed   dstar   group   until   run   obj   

创建线程的几种方式:

 1. 通过继承 Thread 类

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

2. 通过实现Runnable接口

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

3. 通过Callable接口和FutureTask实现有返回值的线程

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

}

 

原理探究:

 

1. 关于第三种方式是如何实现线程执行 实现 Callable 接口中的 call 方法的?

 通过debug 一步一步查看执行过程可以发现

 thread.start方法创建线程,当线程被CPU分配时间片时, Runable实现类中的 run 方法,因为  FutureTask 类实现了 RunnableFuture 接口 该接口继承了 Runnable 和  Future接口

实际上执行的是FutureTask  中的 run 方法,run 方法中执行  Callable接口中run 方法 也就是 自己实现类中的run 方法;

执行流程:

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

  

 

 万事预则立,不预则废~~~加油

并发编程线程基础(一)---线程的创建

标签:ssi   thread   sof   zed   dstar   group   until   run   obj   

原文地址:https://www.cnblogs.com/sunyangCoder/p/13532556.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!