首先我们知道启动一个线程都是通过调用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方法。