问题 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 的区别。