java中创建线程的四种方法
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 使用线程池
1.继承Thread类
/**
继承Thread类,java只能继承一个类,不够灵活
*/
public class MyThread extends Thread{
public void run(){
System.out.println("run方法执行了......");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
System.out.println(myThread.getName()+"启动了...");
}
}
2.实现Runnable接口
public class MyRunnable implements Runnable {
public void run() {
System.out.println("run方法执行了......");
}
public static void main(String[] args) {
Thread myThread = new Thread(new MyRunnable());
myThread.start();
System.out.println(myThread.getName()+"启动了......");
}
}
3.实现Callable接口
实现Callable接口,和Runnable类似,重写call方法,允许返回值,可以抛异常
自定义类,实现Callable接口,自定义泛型“Callable”,就是call方法返回的类型
public class MyCallable implements Callable<String> {
public String call() throws Exception {
System.out.println("call方法执行了......");
return "success";
}
public static void main(String[] args) {
//FutureTask的泛型要和MyCallable call方法返回的类型一致
FutureTask<String> task = new FutureTask<String>(new MyCallable());
Thread thread = new Thread(task);
thread.start();
System.out.println(thread.getName()+"启动了......");
//打印返回结果
try {
String result = task.get();
System.out.println("MyCallable返回结果:"+result);
}catch (Exception e){
e.printStackTrace();
}
System.out.println(task.isDone());
}
}
4.使用线程池
线程池对象获取线程并执行Runnable实例
public class MyRunnable implements Runnable {
public void run() {
System.out.println("run方法执行了......");
}
public static void main(String[] args) {
//使用线程池创建线程
//1.使用Executors获取线程池对象
ExecutorService executorService = Executors.newFixedThreadPool(10);
//2.通过线程池对象获取线程并执行MyRunnable实例
executorService.execute(new MyRunnable());
}
}
线程池对象获取线程并执行Callable实例
public class MyCallable implements Callable<String> {
public String call() throws Exception {
System.out.println("call方法执行了......");
return "success";
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
FutureTask<String> task = new FutureTask<String>(new MyCallable());
executorService.execute(task);
}
}
5. 总结
1. 实现接口和继承Thread类比较
- 接口更适合多个相同的程序的代码的线程去共享同一资源
- 接口可以避免java中的单继承局限性
- 接口代码可以被多个线程共享,代码和线程独立
- 线程池只能放入实现Runnable或Callable接口的线程,不能直接放入继承Thread的类
- 扩充:在java中,每个线程运行至少启动2个线程。一个是main线程,一个是垃圾收集器线程
2.Runnable和Callable接口比较
-
相同点:
两者都是接口
两者都可以来编写多线程程序
两者都需要调用Thread.start()启动线程 -
不同点:
实现Callable接口的线程能返回执行结果;而实现Runnable接口的线程不能返回结果
Callable接口的Call()方法允许抛出异常;而Runnable接口的run()方法不允许抛异常
实现Callable接口的线程可以调用Future.cancel取消执行,而实现Runnable接口的线程不能
注意点:Callable接口支持返回执行结果,此时需要调用FutureTask.get方法实现,此方法会阻塞
主线程直到获取"将来"结果;当不调用此方法时,主线程不会阻塞