上一篇地址:赶紧收藏!2024 年最常见 100道 Java 基础面试题(二十一)-CSDN博客
四十三、线程的run()和start()有什么区别?
在Java中,run()
方法和start()
方法都是与线程(Thread)相关的方法,但它们的作用和行为有所不同:
-
run()
方法:run()
方法是java.lang.Runnable
接口的一部分,用于定义线程要执行的具体任务。当线程被创建并启动后,run()
方法中的代码将被执行。- 如果直接调用一个线程对象的
run()
方法,那么这个线程并不会在新线程中执行,而是在调用run()
方法的当前线程中执行,即它不会产生多线程的效果。
java">class MyThread implements Runnable {public void run() {// 线程执行的代码} } MyThread t = new MyThread(); t.run(); // 直接调用run()方法,不会创建新线程
-
start()
方法:start()
方法是java.lang.Thread
类的方法,用于启动新线程。当调用一个线程对象的start()
方法时,线程将进入可运行状态,Java虚拟机将会在适当的时候调度它的运行。start()
方法实际上会调用线程的run()
方法,但在此之前,它会先执行与线程创建和初始化相关的操作。这意味着run()
方法中的代码将在新线程的上下文中执行。
java">Thread thread = new Thread(new MyRunnable()); thread.start(); // 启动新线程,将会调用MyRunnable的run()方法
-
线程的生命周期:
- 当
start()
方法被调用时,线程的生命周期开始,线程会进入到就绪状态(Runnable),等待JVM调度其执行。 - 当线程的
run()
方法执行完成后,线程结束其生命周期,进入到终止状态(Terminated)。
- 当
-
使用场景:
- 如果你想创建一个线程来执行特定的任务,你应该使用
start()
方法来启动线程。 - 如果你只是想在当前线程中执行某个任务,而不需要创建新线程,你可以直接调用
run()
方法。
- 如果你想创建一个线程来执行特定的任务,你应该使用
总结:
run()
方法是线程执行体,定义了线程要执行的任务。start()
方法是线程的启动器,调用它才会在新线程中执行run()
方法。- 调用
run()
方法不会启动新线程,而start()
方法会启动新线程并调用run()
方法。 - 在使用线程时,应该优先使用
start()
方法来启动线程,而不是直接调用run()
方法。
四十四、创建线程池有哪几种方式?
在Java中,创建线程池主要有以下几种方式,每种方式都适用于不同的场景,并提供了不同级别的控制和灵活性:
-
使用
Executors
类:Executors
类提供了一些工厂方法来创建不同类型的线程池,这些方法内部封装了线程池的创建细节。-
固定大小的线程池:
-
java">ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
-
单线程的线程池:
java">ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
-
可缓存的线程池:
java">ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
-
定时以及单次调度线程池:
java">ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
-
-
使用
ExecutorService
接口的实现类: 直接创建java.util.concurrent
包下ExecutorService
接口的实现类的实例,如ThreadPoolExecutor
。java">int corePoolSize = 3; int maximumPoolSize = 10; long keepAliveTime = 1L; TimeUnit unit = TimeUnit.MINUTES; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); ThreadFactory threadFactory = Executors.defaultThreadFactory(); RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); ExecutorService threadPool = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler );
-
使用
ScheduledThreadPool
类: 如果需要执行定时任务或具有固定延迟的任务,可以使用ScheduledThreadPool
。java">ScheduledExecutorService scheduledThreadPool = new ScheduledThreadPoolExecutor(3);
-
自定义线程池: 如果标准线程池不能满足需求,可以自定义线程池。这涉及到继承
ThreadPoolExecutor
类或者实现Executor
接口。java">class MyThreadPool extends ThreadPoolExecutor {public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);}// 自定义线程池的其他行为 } MyThreadPool myThreadPool = new MyThreadPool(3, 10, 1L, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
-
使用
Executor
接口: 直接实现Executor
接口,提供一个执行任务的方法。java">class MyExecutor implements Executor {public void execute(Runnable command) {// 创建并启动新线程来执行任务} } MyExecutor myExecutor = new MyExecutor();
总结:
Executors
类提供了简便的方法来创建预定义配置的线程池,适合大多数一般用途。ExecutorService
接口和ThreadPoolExecutor
类提供了更多的定制选项,适合需要特定行为的线程池。ScheduledThreadPool
适用于需要执行定时或周期性任务的场景。- 自定义线程池提供了最大的灵活性,但也需要更多的编码工作。
- 选择哪种方式创建线程池,取决于具体的应用需求和对线程池行为的控制程度。