1. 继承 Thread 类
继承 Thread 类,重写 run() 方法。
在主线程中创建 MyThread 类对象,调用 start() 方法启动线程。
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("继承 Thread 创建线程");
}
}
2. 实现 Runnable 接口
创建一个 MyRunnable 内部类实现 Runnable 接口,重写 run() 方法。
在创建 Thread 类对象时传入 MyRunnable 类对象。
也可以不单独写 Runnable 接口的实现类,直接使用 Lambda 表达式完成。
public class ThreadDemo {
public static void main(String[] args) {
//实现 Runnable 接口
Thread t1 = new Thread(new MyRunnable());
t1.start();
//直接使用 Lambda 缩写
new Thread(()->{
System.out.println("用 Lambda 缩写创建线程");
}).start();
}
static class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现 Runnable 接口创建线程");
}
}
}
3. 实现 Callable 接口
创建一个 MyCallable 内部类实现 Callable 接口,重写 call() 方法。
FutureTask 实现了 RunnableFuture,RunnableFuture 继承了 Runnable, Future。
意味着可通过 FutureTask 接收 Callable 中 call 方法的返回值。
并和 Runnable 一样,传入 Thread 中创建线程。
futureTask.get() 方法可以得到线程返回结果,但是该方法是阻塞的。
意味着如果 t1 线程一直在运算,main 线程需要一直等待 t1 的结束,拿到结果才能继续运行。
public class ThreadDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask futureTask = new FutureTask<>(new MyCallable());
Thread t1 = new Thread(futureTask);
t1.start();
//如果 futureTask.get() 没得到结果,代码将一直等着
System.out.println(futureTask.get());
System.out.println("t1 线程执行完成");
}
static class MyCallable implements Callable {
@Override
public Object call() {
System.out.println("实现 Callable 接口创建线程");
return "Callable 返回结果";
}
}
}
4. 使用线程池创建
优点:
降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
提高响应速度。 当任务到达时,任务可以不需要等到线程创建就能立即执行。
提高线程的可管理性。 如果无限制的创建线程,不仅会消耗系统资源,还会降低系统的稳定性,通过线程池可以进行统一的分配,调优和监控。
public class ThreadDemo {
public static void main(String[] args){
//创建固定 5 个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//用线程池执行 100 次任务
for (int i = 0; i < 100; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
}
}