今天看到有人聊多线程的两种创建方式:实现Runnable和继承Thread,然后讨论这两种方式的优缺点。个人认为这个问题应该不需要讨论,直接推荐实现Runnable方式,至于理由,设计者的设计意图就是这么定的,继承Thread属于骚操作。具体看源码注释。
Runnable接口的注释:
1 /** 2 * The <code>Runnable</code> interface should be implemented by any 3 * class whose instances are intended to be executed by a thread. The 4 * class must define a method of no arguments called <code>run</code>. 5 * <p> 6 * This interface is designed to provide a common protocol for objects that 7 * wish to execute code while they are active. For example, 8 * <code>Runnable</code> is implemented by class <code>Thread</code>. 9 * Being active simply means that a thread has been started and has not 10 * yet been stopped. 11 * <p> 12 * In addition, <code>Runnable</code> provides the means for a class to be 13 * active while not subclassing <code>Thread</code>. A class that implements 14 * <code>Runnable</code> can run without subclassing <code>Thread</code> 15 * by instantiating a <code>Thread</code> instance and passing itself in 16 * as the target. In most cases, the <code>Runnable</code> interface should 17 * be used if you are only planning to override the <code>run()</code> 18 * method and no other <code>Thread</code> methods. 19 * This is important because classes should not be subclassed 20 * unless the programmer intends on modifying or enhancing the fundamental 21 * behavior of the class. 22 * 23 * @author Arthur van Hoff 24 * @see java.lang.Thread 25 * @see java.util.concurrent.Callable 26 * @since JDK1.0 27 */
注释说的很明确,如果只是想实现多线程,重写run,那就实现Runnable,如果想定制Thread,如把默认线程优先级改为6,那你就重写Thread。
从面向对象的角度、面向接口编程的角度实现Runnable方式都比继承Thread的方式更合理。
再看看具体实现上有什么区别:
//Thread Thread t = new Thread() { public void run() { System.out.println("Thread"); } }; t.start(); //Runnable Runnable r=new Runnable() { @Override public void run() { System.out.println("Runnable"); } }; Thread t=new Thread(r); t.start();
en。。。Runnable还多比Thread继承方式多写了几行代码,这不重要,可以通过lamdba减少代码量 new Thread(()-> System.out.println("Runnable")).start();
可见上边的代码,实现Runnable接口方式的run方法加了@Override,而继承Thread方式的run方法没有加@Override,为什么,因为开发工具没有给出智能提示,甚至继承Thread方式的run方法都是手动敲的,明显影响码字速度嘛,不加@Override又不正规有木有。
再看源码:
//实现Runnable方式调用构造函数 public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } //继承Thread方式调用构造函数 public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } //最终调用初始化函数 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) { /* Determine if it‘s an applet or not */ /* If there is a security manager, ask the security manager what to do. */ if (security != null) { g = security.getThreadGroup(); } /* If the security doesn‘t have a strong opinion of the matter use the parent thread group. */ if (g == null) { g = parent.getThreadGroup(); } } /* checkAccess regardless of whether or not threadgroup is explicitly passed in. */ g.checkAccess(); /* * Do we have the required permissions? */ 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(); this.target = target; setPriority(priority); if (inheritThreadLocals && parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; /* Set thread ID */ tid = nextThreadID(); }
//Thread类的run方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
如上,实现Runnable方式的定义和执行流程是:
创建Runnable类型对象r,创建Thread对象t,把r放到t的target字段中,执行t的run方法,t调用r的run方法。
继承Thread方式的定义和执行流程是:
创建SubThread类型对象t,t定义run方法,隐藏掉父类的run,执行t的run方法。
两者在执行上并没有多大区别,至于说资源共享上就更没什么区别了。
最后就是说实现Runnable的方式可以实现继承其他父类,而继承Thread的方式不能在继承其他父类,这就涉及到面向对象的定义了。
比如说有个Compute类,实现了Runnable接口,那么可以说这个类的核心还是计算功能,但是拥有了多线程的能力。但是如果这个Compute类继承自Thread,那么这个Compute类的核心更像是为了完成多线程,而计算功能成了附带品。
总是,两种方式都能实现多线程,但还是强烈推荐实现Runnable接口的方式实现多线程吧。
原文:https://www.cnblogs.com/jusha/p/14375622.html