Java创建线程的几种方式
总结:共4种,继承Thread、实现Runnable、实现Callable、使用线程池创建。究其底层,都是采用实现Runnable,重写run()方法。
- 继承Thread类
public class MyThread extends Thread{
public static void main(String[] args) {
MyThread th = new MyThread();
th.start();
}
@Override
public void run() {
System.out.println("thread is running ...");
}
}
注:
- 重写的是run()方法,而不是start()方法。
- 用start()来启动线程,实现了真正意义上的启动线程,此时会出现异步执行的效果,即在线程的创建和启动中所述的随机性。 而如果使用run()来启动线程,就不是异步执行了,而是同步执行,不会达到使用线程的意义。
- 该方法的缺点是无法再继承其他类
- 实现Runnable接口
public class MyThread implements Runnable{
public static void main(String[] args) {
Thread th = new Thread(new MyThread());
th.start();
}
@Override
public void run() {
System.out.println("thread is running ...");
}
}
这种方法更常用
由于Runnable是一个函数式接口,也可以使用lambda表达式实现
public class MyThread{
public static void main(String[] args) {
Thread th = new Thread(()-> System.out.println("hello runnable..."));
th.start();
}
}
- 实现Callable接口,配合FutureTask
public class MyThread implements Callable<String> {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> task = new FutureTask<>(new MyThread());
Thread th = new Thread(task);
th.start();
String result = task.get();
System.out.println(result);
}
@Override
public String call() throws Exception {
return "hello callable";
}
}
这种方法可以拿到线程异步执行的返回值结果
4. 使用线程池创建线程
public class MyThread{
public static void main(String[] args) throws ExecutionException, InterruptedException {
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 10,
60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10),
new ThreadPoolExecutor.AbortPolicy()
);
executor.execute(new Thread(()-> System.out.println("threadPool build a thread")));
}
}
- 不建议使用Executors创建线程池,建议使用ThreadPoolExecutor。因为Executors采用的任务队列能容纳的最大线程数为Integer.Max_Value,容易导致内存爆满。ThreadPoolExecutor可以使用指定大小的任务队列。
- ThreadPoolExecutor的6个关键参数分别是核心线程数、最大线程数、临时线程空闲后的生存时间、时间单位、任务队列、拒绝策略。