问题1:创立线程有多种办法?
初学Java多线程编程的时候,咱们被告知有两种创立多线程的办法:
- 继承Thread类,重写run办法,如例1;
- 实现Runnable接口,如例2;
例1:继承Thread类:
class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread()); } public static void main(String[] args) { MyThread t = new MyThread(); t.start(); }}
例2:实现Runnable接口:
public static void main(String[] args) { Runnable r = () -> { System.out.println(Thread.currentThread()); }; Thread t = new Thread(r); t.start(); }
然而,仔细观察你能够发现,即便实现了Runnable接口,也还须要把它扔进Thread中。所谓实现Runnable接口,仅仅是定义了线程的工作内容而已。
兴许你还听过Callable接口,上面是一种写法:
static class MCall implements Callable<String> { @Override public String call() { return "hello"; } } public static void main(String[] args) { Callable<String> callable = new MCall(); FutureTask<String> task = new FutureTask<>(callable); Thread t = new Thread(task); t.start(); }
看,依然须要创立Thread对象。
不管用什么把戏,最终都得老老实实创立Thread或其子类实例。Thread是创立线程的惟一形式。
线程池中的线程仍然是Thread子类实例。
问题2:new Thread()是创立了一个线程吗?
上面创立了一个Thread实例
Thread t = new Thread();
到此,咱们仅仅失去一个Thread对象,但还没有创立线程。这句话可能让你意外。咱们先通过一个例子来看看。
static class MThread extends Thread { @Override public void run() { // 打印以后线程名 System.out.println(Thread.currentThread().getName()); } } public static void main(String[] args) { MThread thread = new MThread(); thread.run(); // 留神这里调的是run办法 }
猜猜打印的后果是什么?后果是——main
还记得在初学java的时候,老师通知咱们要调用start,而不是run,这两者有什么区别?
答案是, start办法外部调用了本地办法start0,这个本地办法才真真切切触发操作系统去创立线程(内核线程),而后,jvm调用run办法运行在新线程上。
如果间接调用run,只是像一般办法一样,并不会创立线程,run办法依然运行在以后线程中,所以下面运行的后果是main。
小结
通过这篇文章,咱们晓得了:
- 在java中,创立线程必须通过创立Thread或其子类实例并且调用start办法来实现;
- start和run的区别。