案例代码一
@Slf4j public class Client { public static void main(String[] args) { MyThread myThread = new MyThread(); myThread.start(); } } class MyThread extends Thread{ @Override public void run() { super.run(); } }
线程调用 start() 方法之后,操作系统的任务调度器就会对线程进行调度,线程进入就绪状态,然后等待分配 CPU 时间片,如果线程分配到了 CPU 时间片,操作系统底层就会执行 run() 方法
MyThread 类继承自 Thread 类,同时重写了 run 方法,对于线程来说,如果它分配到了 CPU 时间片,操作系统底层最终调用的是当前线程类的 run() 方法(可以简单的理解为运行状态下的线程只认 run() 方法)
如果多写一个 MyThread 类不够优雅,那么可以使用匿名内部类的方式
@Slf4j public class Client { public static void main(String[] args) { Thread t1 = new Thread() { @Override public void run() { log.info("t1 start..."); } }; } }
案例代码二
@Slf4j public class Client { public static void main(String[] args) { Runnable runnable = ()->{ log.info("t1 start..."); }; Thread t1 = new Thread(runnable, "t1"); t1.start(); } }
使用 Runnable + Thread 方式实现的多线程,run() 方法是如何被调用的呢
我们跟踪 new Thread(runnable,"t1") 这段代码
public Thread(Runnable target, String name) { init(null, target, name, 0); } private void init(ThreadGroup g, Runnable target, String name,long stackSize) { init(g, target, name, stackSize, null, true); } private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) { if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { if (security != null) { g = security.getThreadGroup(); } if (g == null) { g = parent.getThreadGroup(); } } g.checkAccess(); if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } } g.addUnstarted(); this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext(); // 将传进来的 Runnable 实现类对象赋值给成员变量 target this.target = target; setPriority(priority); if (inheritThreadLocals && parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); this.stackSize = stackSize; tid = nextThreadID(); }
通过上面的源码得知,我们使用 Thread 带参构造方法传递进来的 Runnable 接口的实现类对象最终赋值给了 Thread 类的成员变量 Runnable target
当线程调用 start() 方法会进入到就绪状态,紧接着获取到 CPU 时间片之后会进入运行状态,运行状态的线程只会去调度当前线程类的 run() 方法
上面案例中当前线程类是 Thread 类的一个实例,找到 Thread run 方法
@Override public void run() { // 如果 Runnable 类型的成员变量不为 null,则调用成员变量的 run() 方法 if (target != null) { target.run(); } }
而通过上面我们已经知道了成员变量的 target 就是我们传递进来的 runnable,所以最终调用的是 runnable 对象的 run 方法
案例代码三
@Slf4j public class Client { public static void main(String[] args) { FutureTask<String> futureTask = new FutureTask(()->{ log.info("t1 start..."); return "hello xiao mao mao!"; }); Thread t1 = new Thread(futureTask, "t1"); t1.start(); } }
在跟代码之前先看一下 FutureTask 的继承体系吧
通过整个体系可以看出 FutureTask 也是 Runnable 接口的一个具体实现类
通过案例二可以得知使用 Thread t1 = new Thread(futureTask, "t1") 这种方式创建线程对象的时候,如果线程进入运行状态,实际上调用的是 Runnable 实现类的 run() 方法,而我们这里的 FutureTask 就是 Runnable 接口的实现类,所以运行状态的线程最终调用的是 futureTask 的 run() 方法
接着看一下 FutureTask 类的 run() 方法是怎么实现的
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset,null, Thread.currentThread())) return; try { // 将成员变量 callable 赋值给变量 c Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { // 调用 Callable 实现类对象的 call 方法 result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { runner = null; int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
从源码可以看出在 futureTask 对象的 run() 方法中实际上是 Callable 接口实现类的 call() 方法在执行
所以 Callable + FutureTask + Thread 这种方式下,当线程处于运行状态下时,真正执行业务逻辑的是 Callable 实现类的 call() 方法,该方法是对 run() 方法的一个增强,call() 方法可以抛出异常,也可以有返回值,而这些特性 run() 方法都不支持
@FunctionalInterface public interface Callable<V> { V call() throws Exception; }
标签:run,Thread,t1,线程,null,方法,public From: https://www.cnblogs.com/xiaomaomao/p/17028986.html