实现多线程通常有以下四种方式:
- 继承 Thread 类。
- 实现 Runnable 接口。
- 实现 Callable 接口。
- 线程池实现多线程。
继承 Thread 类:
public class ThreadDemo extends Thread{
@Override
public void run(){
System.out.println("Thread 类实现多线程,线程名称:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
ThreadDemo threadDemoOne=new ThreadDemo();
threadDemoOne.start();
ThreadDemo threadDemoTwo=new ThreadDemo();
threadDemoTwo.start();
}
}
运行结果:
Thread 类实现多线程,线程名称:Thread-1
Thread 类实现多线程,线程名称:Thread-0
继承 Thread 类实现多线程的优缺点:
- 优点:实现简单,只需要继承 Thread 类,实现 run 方法即可,实际启动线程还是使用 start 方法,start() 方法是一个 native 方法,它将启动一个新线程,并执行 run() 方法。
- 缺点:我们知道 Java 的单继承的,如果类已经继承了其他的类则不能继承 Thread 类,而且也不能获取线程的返回值。
Thread 类本质上是实现了 Runnable 接口,如下:
实现 Runnable 接口:
public class RunnableDemo implements Runnable {
@Override
public void run() {
System.out.println("实现 Runnable 接口实现多线程,线程名称:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
System.out.println("当前线程名称:" + Thread.currentThread().getName());
Thread thread = new Thread(new RunnableDemo());
thread.start();
}
}
执行结果:
当前线程名称:main
实现 Runnable 接口实现多线程,线程名称:Thread-0
实现 Runnable 接口实现多线程的优缺点:
- 优点:实现简单,实现 Runnable 接口,重写 run 方法即可。
- 缺点:每次创建一个线程就必须创建一个 Runnable 的实现类,而且也不能获取线程的返回值。
实现 Callable 接口:
public class CallableDemo implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("当前线程的名称是:" + Thread.currentThread().getName());
return "返回值";
}
public static void main(String[] args) {
FutureTask<String> futureTask = new FutureTask<>(new CallableDemo());
System.out.println("准备开始启动线程,当前线程的名称是:" + Thread.currentThread().getName());
new Thread(futureTask).start();
try {
String str = futureTask.get();
System.out.println("线程的返回值:" + str);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
执行结果:
准备开始启动线程,当前线程的名称是:main
当前线程的名称是:Thread-0
线程的返回值:返回值
实现 Callable 接口实现多线程的优缺点:
- 优点:可以获取多线程的返回值,这是前面两种实现多线程的方法做不到的事情。
- 缺点:每次创建一个线程就必须创建一个 Callable 的实现类。
线程池实现多线程:
public class ExecutorServiceDemo {
public static void main(String[] args) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(100);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("executorService-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
for (int a = 0; a < 10; a++) {
executor.execute(() -> {
System.out.println("当前线程名称:" + Thread.currentThread().getName());
});
}
}
}
执行结果:
当前线程名称:executorService-2
当前线程名称:executorService-3
当前线程名称:executorService-4
当前线程名称:executorService-4
当前线程名称:executorService-4
当前线程名称:executorService-4
当前线程名称:executorService-4
当前线程名称:executorService-1
当前线程名称:executorService-3
当前线程名称:executorService-2
使用线程池实现多线程的优点:
- 使用线程池实现多线程,可以实现线程的重复使用,就可以避免因线程创建销毁带来的资源消耗。
- 提高响应速度,因为线程池的线程是创建好了的,故任务一到达马上就可以开始执行。
- 使用线程池可以提高线程的可控性,线程的创建和销毁不仅会增加系统的消耗,同时如果线程创建不当,会降低系统的额稳定性,线程池可以对线程进行统一管理。
如有错误的地方欢迎指出纠正。