Java的线程创建方法
在Java当中,最基本的线程创建方法有两种,一种是通过继承Thread类,重写run方法:
class MyThread extends Thread{
@Override
public void run() {
System.out.println("this is MyThread!");
}
}
public static void main(String[] args) {
Thread myThread=new MyThread();
myThread.start();
}
另外一种是实现Runnable接口,重写run方法:
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("this is MyRunnable!");
}
}
public static void main(String[] args) {
new Thread(new MyRunnable()).start();
}
上述两种方式都能创建一个线程,并启动运行。查看Thread的源码,发现Thread是一个Runnable的子类,因此需要实现Ruannable的run方法,所以我们继承Thread重写的run方法实际上就是Runnable的run方法。
class Thread implements Runnable {
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
另外,Thread内还有一个start方法,从start方法的注释可以知道,调用该方法时,虚拟机会创建一个线程,并默认执行Thread的run方法。
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* */
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
//一个本地方法,java本地调用的接口,用于创建线程
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
因此,两种线程创建方式都是利用了在执行start方法启动线程时,会默认调用run方法的特性:
- 我们通过继承Thread类重写run方法的方式创建线程时,调用start方法,虚拟机创建了线程,由于我们重写了run方法,因此执行的是我们的方法,而不是Thread类内target属性的run方法;
- 我们通过实现Runnable接口创建线程时,Thread的构造函数会将我们实现的Runnable对象,赋值给Thread类内的target属性,调用Thread的start方法,由虚拟机创建线程,因为我们没有重写Thread的run方法,所以执行的是Thread的run方法,但是该方法调用了target的run方法,因此我们实现的Runnable的run方法得以执行
Callable接口说明
上述的两种线程创建方法都重写了run方法,但是run方法没有返回参数,对于需要线程返回计算结果的情况,
JDK提供了Callable的接口,Callable接口定义了一个带返回值的call方法,并且返回值是类型参数:
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
因此,通过Callable接口,再结合线程池,可以实现线程返回一个Future对象,通过该对象可以获取计算结果。注意:Future的get方法,是一个阻塞方法。
class MyCallable implements Callable<String>{
@Override
public String call() throws Exception{
Thread.sleep(2000);
return " world!";
}
}
public static void main(String[] args) throws Exception{
ExecutorService executorService=Executors.newSingleThreadExecutor();
MyCallable myCallable=new MyCallable();
Future<String> result =executorService.submit(myCallable);
System.out.println("hello "+result.get());
}