除去线程池,我们应该都知道java多线程的实现方式有三种:继承Thread类,实现Runnable接口,实现Callable接口。本文暂不涉及线程池,主要说一下以上三种方式。
第一种:继承Thread类
Thread类在java.lang包中。我们只需要继承Thread类,重写run()方法,就可以实现多线程了。 示例代码如下:
public class ThreadDemo extends Thread {
private String name;
public ThreadDemo(String name) {
this.name = name;
}
public void run() {
System.out.println("thread name is:" + name);
}
public static void main(String[] args) {
ThreadDemo t1 = new ThreadDemo("first thread");
ThreadDemo t2 = new ThreadDemo("second thread");
ThreadDemo t3 = new ThreadDemo("third thread");
t1.start();
t2.start();
t3.start();
}
}
执行结果如下(执行结果可能会不同,为何不同,可以思考一下):
thread name is:first thread
thread name is:third thread
thread name is:second thread
看过Thread源码的都知道,Thread类是实现了Runnable接口的。
第二种:实现Runnable接口
Runnable仅仅是一个接口,它只包含run()方法,源码如下:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
实现示例如下:
public class RunnableDemo {
public static void main(String[] args) {
RunnableImpl r1 = new RunnableImpl("first runnable");
RunnableImpl r2 = new RunnableImpl("second runnable");
RunnableImpl r3 = new RunnableImpl("third runnable");
new Thread(r1).start();
new Thread(r2).start();
new Thread(r3).start();
}
}
class RunnableImpl implements Runnable {
public String name;
public RunnableImpl(String name){
this.name = name;
}
@Override
public void run() {
System.out.println("runnable name is:" + name);
}
}
//lambda 实现方式更简单
new Thread(() ->{
String name = "first runnable";
System.out.println("runnable name is:" + name);
}).start();
以上两种启动线程的方式原理是一样的。首先都是调用本地方法启动一个线程,其次是在这个线程里执行目标对象的run()方法。那么这个目标对象是什么呢?我们来看看Thread类的run()方法的实现是:
public void run() {
if (target != null) {
target.run();
}
}
如果采用的是继承Thread类的方式,那么这个target就是线程对象自身,如果采用的是实现Runnable接口的方式,那么这个target就是实现了Runnable接口的类的实例。
第三种:实现Callable接口
与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。 Callable位于java.util.concurrent包下,它也是一个接口,在它里面也只声明了一个方法,只不过这个方法叫做call():
public interface Callable<V> {
V call() throws Exception;
}
这是一个泛型接口,call()方法返回的类型就是传递进来的V类型。 实现示例如下:
public class CallableDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Integer> implCallable = new CallableImpl();
FutureTask<Integer> futureTask = new FutureTask<>(implCallable);
new Thread(futureTask).start();
long start = System.currentTimeMillis();
System.out.println("start...."+ start);
System.out.println("result:"+futureTask.get());
long end = System.currentTimeMillis();
System.out.println("end......"+ end +",cost:"+ (end - start) +"ms");
}
}
class CallableImpl implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int result = 0;
for(int i=0;i<10;i++){
result += i;
}
Thread.sleep(2000);
return result;
}
}
思考:FutureTask的使用方式。