实现线程的三种方式分别为:
继承Thread类,重写run()方法,无返回值(Thread类也实现了Runnable接口)
实现Runnable接口,覆写run()方法,无返回值
实现Callable接口,覆写call()方法,有返回值,要配合FutureTask类的使用
1.继承Thread类
//线程类
public class MyThread extends Thread{
//重写run()方法
public void run() {
try {
Thread.sleep(2000); //该线程沉睡2秒后再执行,sleep()的单位是毫秒
System.out.println("我是子线程,现在运行结束了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//主类
public class Main {
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread );
thread.start(); //启动线程
System.out.println("Main 线程已经结束");
}
}
执行此代码后,其实有两个线程在同时运行,一个是main函数的线程,一个是自己的线程myThread,下面是运行代码结果截图。
说明了主线程并不是一定比子线程结束的晚。
(注:启动线程只能用start()方法,如果是直接调用run()方法的话,那就不是并发执行,而是串行执行的了)
2 .实现Runnable接口
//线程类
public class MyThread implements Runnable{
//重写run()方法
@Override
public void run() {
try {
Thread.sleep(2000); //该线程沉睡2秒后再执行,sleep()的单位是毫秒
System.out.println("我是子线程,现在运行结束了");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//主类同上
一般不推荐使用第一种方法,因为java规定了不能多继承,一个类只能被继承一次,这就大大的限制了多线程的创建,但使用接口就没有限制。
3 . 实现callable接口
因为这种创建线程的方式是有返回值的,需要 FutureTask 类的支持
//定义一个线程类来计算[m,n]区间的数的和
public class SumTask implements Callable<Integer> {
private int startNumber; //起始数字
private int endNumber; //终止数字
public SumTask(int startNumber, int endNumber){
this.startNumber = startNumber;
this.endNumber = endNumber;
}
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = startNumber; i < endNumber;i++){
sum += i;
}
return sum;
}
}
//主类
public class Main {
public static void main(String[] args) {
//创建线程,计算1-100的和
SumTask sumTask = new SumTask(1,100);
FutureTask<Integer> futureTask = new FutureTask<>(sumTask);
//启动线程
new Thread(futureTask).start();
try {
Integer sum = futureTask.get(); //得到结果
System.out.println("1到100的和为:"+sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
FutureTask 类实现了Runnable和Future接口,而callable只是一个单纯的接口,所以要启动线程还得依靠FutureTask 类的支持。