Oracle官方文档对创建线程的说明
-
Java SE 8 API文档: docs.oracle.com/javase/8/do…
请查看java.lang.Thread的类说明文档。
-
- 将类声明为Thread的子类,并重写run方法。
官方原话:There are two ways to create a new thread of execution. One is to declare a class to be a subclass of
Thread
. This subclass should override therun
method of classThread
./** * 实现线程的第一个方式 继承Thread * @author yiren */ public class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + " Thread running..."); } public static void main(String[] args) throws IOException { new MyThread().start(); System.in.read(); } } 复制代码
-
- 实现Runnable接口,并实现run方法。
官方原话:The other way to create a thread is to declare a class that implements the
Runnable
interface. That class then implements therun
method.
/**
* 实现线程的第二个方式 实现Runnable接口
* @author yiren
*/
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Runnable running...");
}
public static void main(String[] args) throws IOException {
new Thread(new MyRunnable()).start();
System.in.read();
}
}
复制代码
两种发方法的优缺点
-
- 从代码的结构上去考虑,具体线程执行的任务是run方法中的代码,相当于业务代码,它应该和我们线程的创建解耦。
- 如果继承
Thread
,每次想建一个异步任务,我们都需要去建立一个独立的线程。而创建一个线程的消耗是比较大的,如果是使用Runnable
,我们就可以很好得利用线程池之类的工具,这样可以大大减少创建和销毁线程的损耗。节省资源。 - 由于Java是单继承,继承了
Thread
的类过后,该类就无法再继承其他类,大大限制了可扩展性。
/* What will be run. */
private Runnable target;
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 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) {
......
this.target = target;
......
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
复制代码
-
两种方法的本质(由上面的Thread类的源代码可知)
- 继承
Thread
是整个run()
方法被重写 - 实现
Runnable
最终是Runnable
的run
方法被target.run()
调用
- 继承
-
如果两种方式都用会有什么效果呢?
/** * @author yiren */ public class MyThreadAndRunnable { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " runnable running..."); } } ) { @Override public void run() { System.out.println(Thread.currentThread().getName() + " thread running..."); } }; // 这个地方应该是执行重写Thread类的run方法中的逻辑! thread.start(); } } 复制代码
- 很明显,上面说了不重写
Thread
的run()
方法就是调用target.run()
,如果重写那也就没有调用target.run()
了。
- 很明显,上面说了不重写
-
准确来说,创建线程只有一种方式,那就是构建
Thread
类,而实现线程的执行单元有两种方法,就是上面说的两种。
其他说法:
-
线程池创建线程
/** * wrong 线程池创建 * * @author yiren */ public class ThreadPoolExample { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { executorService.submit(() -> { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); }); } } } // Executors中的DefaultThreadFactory static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon()) t.setDaemon(false); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); return t; } } 复制代码
- 由上
newThread()
方法可知,即使是线程池,本质上还是使用Thread
的创建线程。
- 由上
-
Callable和FutureTask创建线程
-
由上UML图可知,实际上内部还是使用的Thread和Runnable来实现的。
-
定时器Timer
/** * @author yiren */ public class TimerExample { public static void main(String[] args) { Timer timer = new Timer(); // 每隔1s打印下自己的名字 timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " timer running..."); } }, 1000, 1000); } } 复制代码
- 它的TimerTask其实也是实现了Runnable接口,可以看下
TimerTask
这个抽象类
- 它的TimerTask其实也是实现了Runnable接口,可以看下
-
匿名内部类、Lambda表达式 (本质也是一样的)
/** * 匿名内部类 * @author yiren */ public class AnonymousInnerClassExample { public static void main(String[] args) { new Thread() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }.start(); new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }).start(); } } /** * lambda表达式 * @author yiren */ public class LambdaExample { public static void main(String[] args) { new Thread(() -> System.out.println(Thread.currentThread().getName())).start(); } } 复制代码
关于我
- 坐标杭州,普通本科在读,计算机科学与技术专业,20年毕业。
- 主要做Java开发,会写点Golang、Shell。对微服务、大数据比较感兴趣,预备做这个方向。
- 目前处于菜鸟阶段,各位大佬轻喷,小弟正在疯狂学习。
- 欢迎大家留言交流!!!