java创建线程的三种方式——附源码说明

首先我们知道启动一个线程都是通过调用Thread类的start()来开启一个新线程,那么我们就来一起看看Thread类的start()方法源码:

    /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    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 */
            }
        }
    }

    private native void start0();

start方法做了两件事:1、将此线程加入线程组中,2、启动这个线程。由于开启线程是通过start0()这个native方法,我们看不到里面的细节,但是通过注释 —— the Java Virtual Machine calls the run method of this thread —— 我们可以知道run方法其实就相当于是个job,线程就是执行这个job的程序,专门为run方法服务的。所以后面三种方式不管那种其实都是围绕着run方法进行实现这个线程的“job”。

1、通过继承Thread类,覆盖run方法创建线程

  这种方式最粗暴简洁,直接给这个线程分配了“job”。

2、通过传入Runnable类型对象创建线程。

  

 1     public Thread(Runnable target) {
 2         init(null, target, "Thread-" + nextThreadNum(), 0);
 3     }
 4 
 5     private void init(ThreadGroup g, Runnable target, String name,
 6                       long stackSize) {
 7         init(g, target, name, stackSize, null, true);
 8     }
 9 
10 
11     /**
12      * Initializes a Thread.
13      *
14      * @param g the Thread group
15      * @param target the object whose run() method gets called
16      * @param name the name of the new Thread
17      * @param stackSize the desired stack size for the new thread, or
18      *        zero to indicate that this parameter is to be ignored.
19      * @param acc the AccessControlContext to inherit, or
20      *            AccessController.getContext() if null
21      * @param inheritThreadLocals if {@code true}, inherit initial values for
22      *            inheritable thread-locals from the constructing thread
23      */
24     private void init(ThreadGroup g, Runnable target, String name,
25                       long stackSize, AccessControlContext acc,
26                       boolean inheritThreadLocals) {
27         if (name == null) {
28             throw new NullPointerException("name cannot be null");
29         }
30 
31         this.name = name;
32 
33         Thread parent = currentThread();
34         SecurityManager security = System.getSecurityManager();
35         if (g == null) {
36             /* Determine if it's an applet or not */
37 
38             /* If there is a security manager, ask the security manager
39                what to do. */
40             if (security != null) {
41                 g = security.getThreadGroup();
42             }
43 
44             /* If the security doesn't have a strong opinion of the matter
45                use the parent thread group. */
46             if (g == null) {
47                 g = parent.getThreadGroup();
48             }
49         }
50 
51         /* checkAccess regardless of whether or not threadgroup is
52            explicitly passed in. */
53         g.checkAccess();
54 
55         /*
56          * Do we have the required permissions?
57          */
58         if (security != null) {
59             if (isCCLOverridden(getClass())) {
60                 security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
61             }
62         }
63 
64         g.addUnstarted();
65 
66         this.group = g;
67         this.daemon = parent.isDaemon();
68         this.priority = parent.getPriority();
69         if (security == null || isCCLOverridden(parent.getClass()))
70             this.contextClassLoader = parent.getContextClassLoader();
71         else
72             this.contextClassLoader = parent.contextClassLoader;
73         this.inheritedAccessControlContext =
74                 acc != null ? acc : AccessController.getContext();
75         this.target = target;
76         setPriority(priority);
77         if (inheritThreadLocals && parent.inheritableThreadLocals != null)
78             this.inheritableThreadLocals =
79                 ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
80         /* Stash the specified stack size in case the VM cares */
81         this.stackSize = stackSize;
82 
83         /* Set thread ID */
84         tid = nextThreadID();
85     }

通过上面的源码我们可以看到,当你用 Thread t = new Thread(runnable); 创建线程时会调用Thread类的init方法,最关键的是第75行,将传进来的runnable对象赋给Thread类的target属性,这个时候再看看我们的“job”——也就是run方法:

 1     /**
 2      * If this thread was constructed using a separate
 3      * <code>Runnable</code> run object, then that
 4      * <code>Runnable</code> object's <code>run</code> method is called;
 5      * otherwise, this method does nothing and returns.
 6      * <p>
 7      * Subclasses of <code>Thread</code> should override this method.
 8      *
 9      * @see     #start()
10      * @see     #stop()
11      * @see     #Thread(ThreadGroup, Runnable, String)
12      */
13     @Override
14     public void run() {
15         if (target != null) {
16             target.run();
17         }
18     }

如果target不为null,那么我们就执行target的run方法,这种方式就相当于job由用户写好,然后交给线程去执行。

3、通过传入FutureTask类型对象创建线程

FutureTask实现了Runnable接口,所以传入FutureTask类型对象和传入Runnable类型的对象本质上原理一样,只不过FutureTask可以看作是加强版的Runnable,多了一个存储返回值和获取返回值的功能。

既然FutureTask实现了Runnable接口,那么一定实现了run方法,直接上源码:

 1     public void run() {
 2         if (state != NEW ||
 3             !UNSAFE.compareAndSwapObject(this, runnerOffset,
 4                                          null, Thread.currentThread()))
 5             return;
 6         try {
 7             Callable<V> c = callable;
 8             if (c != null && state == NEW) {
 9                 V result;
10                 boolean ran;
11                 try {
12                     result = c.call();
13                     ran = true;
14                 } catch (Throwable ex) {
15                     result = null;
16                     ran = false;
17                     setException(ex);
18                 }
19                 if (ran)
20                     set(result);
21             }
22         } finally {
23             // runner must be non-null until state is settled to
24             // prevent concurrent calls to run()
25             runner = null;
26             // state must be re-read after nulling runner to prevent
27             // leaked interrupts
28             int s = state;
29             if (s >= INTERRUPTING)
30                 handlePossibleCancellationInterrupt(s);
31         }
32     }

run方法主要是执行Callable对象的call方法(上方源码第12行),接受call方法的返回值,并调用set方法将result存储起来。

    /**
     * Sets the result of this future to the given value unless
     * this future has already been set or has been cancelled.
     *
     * <p>This method is invoked internally by the {@link #run} method
     * upon successful completion of the computation.
     *
     * @param v the value
     */
    protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            outcome = v;
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            finishCompletion();
        }
    }

set方法主要是将返回值赋给outcome属性,当调用FutureTask的get方法时,会先判定线程是否正常结束,如果正常结束会将outcome返回。否则会抛出异常。

 1     /**
 2      * Creates a {@code FutureTask} that will, upon running, execute the
 3      * given {@code Callable}.
 4      *
 5      * @param  callable the callable task
 6      * @throws NullPointerException if the callable is null
 7      */
 8     public FutureTask(Callable<V> callable) {
 9         if (callable == null)
10             throw new NullPointerException();
11         this.callable = callable;
12         this.state = NEW;       // ensure visibility of callable
13     }

callable对象是创建FutureTask对象时传进来的,所以这种方式的“job”来自Callable对象的call方法。

  

原文地址:https://www.cnblogs.com/leonandyou/p/15427053.html