在Java中,创建线程有以下几种方式:
通过实现 Runnable 接口;
通过继承 Thread 类本身;
通过 Callable 和 Future 创建线程。
通过实现 Runnable 接口来创建线程
创建线程最简单的方式就是直接实现Runnable接口,该接口定义了一个run()方法,在我们的实现类中通过对该方法的实现来定义我们自己的任务,这样使得我们在创建并启动线程之后能够执行我们自己的任务。比如我们要执行一个倒计时的任务,我们就可以像下面的代码一样实现:
public class RunnableDemo implements Runnable {
@Override
public void run() {
System.out.println("倒计时开始:");
for(int i = 0; i < 10 ; i++){
System.out.println(10-i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread thread = new Thread(new RunnableDemo(),"Runnable-Thread");
thread.start();
}
}
通过继承Thread来创建线程
创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类(关于Thread类我们会在后续的文章中详细阐述),然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。
通过继承Thread重写上面的倒计时任务如下:
public class ThreadDemo extends Thread {
public void run() {
System.out.println("倒计时开始:");
for(int i = 0; i < 10 ; i++){
System.out.println(10-i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
ThreadDemo thread = new ThreadDemo();
thread.start();
}
}
通过 Callable 和 Future 创建线程
Runnable是执行工作的独立任务,但是他不返回任何值,如果你希望任务在完成时能够返回一个值,那么可以实现Callable接口来实现。Callable接口是一种具有类型参数的泛型接口,通过查看它的源码我们可以发现,它的类型参数所表示的是从call()中返回的值的类型。Callable类型的任务可以有两种执行方式:
借助FutureTask执行
借助Executor来运执行
借助FutureTask执行
创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
public class CallableThreadDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("线程在进行计算");
Thread.sleep(1000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<Integer> mycallabletask = new CallableThreadDemo();
FutureTask<Integer> futuretask= new FutureTask<Integer>(mycallabletask);
new Thread(futuretask).start();
System.out.println("返回值:"+futuretask.get());
}
}
借助Executor来运执行
借助Executor必须使用ExecutorService.submit()方法调用它,下面是对上一个实例的改造:
public class CallableThreadDemo2 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("线程在进行计算");
Thread.sleep(1000);
int sum = 0;
for(int i=0;i<100;i++)
sum += i;
return sum;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService exec = Executors.newCachedThreadPool();
Future<Integer> future = exec.submit(new CallableThreadDemo2());
System.out.println("返回值:"+ future.get());
exec.shutdown();
}
}
三种方式对比
采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
参考:
http://www.runoob.com/java/java-multithreading.html
《java编程思想》