在Java中如果要创建线程的话一般方法有四种:
- 继承Thread
- 实现Runnable接口
- 实现Callable接口
- 线程池
一:继承Thread
public class CreateThread1 extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
CreateThread1 t1 = new CreateThread1();
t1.start();
System.out.println(Thread.currentThread().getName());
}
}
通过继承Thread并重写Thread中的run方法实现,在run方法中定义需要执行的任务,然后创建该类对象调用start方法启动线程。
二:实现Runnable接口
public class CreateThread2 implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) {
CreateThread2 c = new CreateThread2();
Thread t = new Thread(c);
t.start();
System.out.println(Thread.currentThread().getName());
}
}
通过实现Runnable接口,并实现接口中定义的run方法(run方法中写需要执行的任务),创建该类对象,然后创建一个Thread对象来“载”一下该类的实例,调用start方法启动线程(通知操作系统任务调度器以多线程异步的方式调用run方法)。Thread实际也实现了Runnable接口。
三:实现Callable接口
public class CreateThread3 implements Callable {
public Object call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "SUCCESS";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
CreateThread3 c = new CreateThread3();
FutureTask<String> future = new FutureTask<String>(c);
Thread t = new Thread(future);
t.start();
System.out.println(Thread.currentThread().getName());
System.out.println("子任务返回===>" + future.get());
}
}
通过实现Callable接口,实现Callable中的call方法,这里的call方法就类似于上面两种情况中的run方法。 在call方法中实现需要执行的任务代码。创建一个FutureTask对象,然后创建一个Thread对象来“载”一下FutureTask对象调用start()方法将该线程注册进操作系统的任务调度器中。 通过该方式创建线程还有一个好处就是可以调用FutureTask的get()方法可以获取子任务的返回值(返回类型在实现Callable接口的时候通过泛型指定)。 注意在调用get()方法的时候,get方法所在的线程会阻塞,同步的等待子线程执行完毕获得执行结果后才继续向下面执行。
四:线程池的方式创建线程
public class CreateThread4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
//提交无返回值的线程任务
executorService.submit(new Runnable() {
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
//提交有返回值的线程任务
Future<String> submit = executorService.submit(new Callable<String>() {
public String call() {
System.out.println(Thread.currentThread().getName());
return "SUCCESS";
}
});
System.out.println(submit.get()); //获取返回值
System.out.println(Thread.currentThread().getName());
executorService.shutdown(); //关闭线程池
}
}
创建线程池的方式有很多种方式,后面具体写文章介绍线程池。 这里先是通过Executors工具类创建一个固定线程数的10的线程池,然后像线程池里面提交一个子线程。同时通过这种方式还支持有返回结果的提交方式。
总结:
实际开发中不建议直接通过一,二,三的方式直接创建线程,而是建议通过线程池的方式创建线程,这样避免线程过多导致服务器宕机,通过线程池的方式便于管理和对线程的更大化利用。