Java 创建线程三种方式
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用三种方式来创建线程
(1)继承Thread类创建线程
(2)实现Runnable接口创建线程
(3)使用Callable和Future创建线程
1、继承Thread类创建线程
创建此类线程一般需要以下三步:
(1)定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。
(2)创建Thread子类的实例,也就是创建了线程对象
(3)启动线程,即调用线程的start()方法
实例:
package Thread;
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("MyThread 线程启动成功!");
}
public static void main(String args[]){
//创建线程对象
MyThread myThread = new MyThread();
//启动线程
myThread.start();
}
}
运行结果:
MyThread 线程启动成功!
2、实现Runnable接口创建线程
一般三个步骤:
(1)定义Runnable接口的实现类,一样要重写run()方法,这个run()方法和Thread中的run()方法一样是线程的执行体
(2)创建Runnable实现类的实例,并用这个实例作为Thread的target来创建Thread对象,这个Thread对象才是真正的线程对象
(3)通过调用线程对象的start()方法来启动线程
实例:
package Thread;
//实现Runnable 接口,并重写run()方法
public class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println("MyThread2 线程启动成功!");
}
public static void main(String args[]){
//创建线程实例
Thread thread = new Thread(new MyThread2());
//启动线程
thread.start();
}
}
运行结果:
MyThread2 线程启动成功!
3、使用Callable和Future创建线程
(1)先来了解一下Callable 接口
Callable是类似于Runnable的接口,实现Callable接口的类和实现Runnable的类都是可被其他线程执行的任务。Callable接口的定义如下:
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的类型参数是返回值的类型。例如:
Callable<Integer>表示一个最终返回Integer对象的异步计算。
(2)Future保存异步计算的结果。实际应用中可以启动一个计算,将Future对象交给某个线程,然后执行其他操作。Future对象的所有者在结果计算好之后就可以获得它。Future接口具有下面的方法:
public interface Future<V> {
//可以用cancel方法取消该计算。如果计算还没有开始,它被取消且不再开始。
//如果计算处于运行之中,那么如果mayInterrupt参数为true,它就被中断
boolean cancel(boolean mayInterruptIfRunning);
//判断是够被取消
boolean isCancelled();
//如果计算还在进行,isDone方法返回false;如果完成了,则返回true。
boolean isDone();
//调用被阻塞,直到计算完成
V get() throws InterruptedException, ExecutionException;
//设置等待时间,get方法的调用超时,抛出一个TimeoutException异常
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
(3) FutureTask包装器是一种非常便利的机制,同时实现了Future和Runnable接口。FutureTask有2个构造方法
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
创建线程的步骤一般如下:
(1)创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例;
(2)使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值
(3)使用FutureTask对象作为Thread对象的target创建并启动线程(因为FutureTask实现了Runnable接口)
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
public class Thread3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> future = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("线程启动成功!");
return 1;
}
});
new Thread(future).start();
System.out.println("或得线程返回值为:" + future.get());
}
}
结果:
线程启动成功!
或得线程返回值为:1
4、总结
(1)实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法有返回值,后者线程执行体run()方法无返回值;
(2)基于Java单继承的原因,推荐使用第二或第三种创建线程;