面试题答案
一键面试创建多线程的两种常见方式
- 继承Thread类:
- 定义一个类继承
Thread
类。 - 重写
run()
方法,在该方法中编写线程执行的代码。 - 创建该类的实例,调用
start()
方法启动线程。 示例代码:
- 定义一个类继承
class MyThread extends Thread {
@Override
public void run() {
System.out.println("This is a thread created by extending Thread class.");
}
}
public class Main {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
}
}
- 实现Runnable接口:
- 定义一个类实现
Runnable
接口。 - 实现
run()
方法,编写线程执行的代码。 - 创建该类的实例,将其作为参数传递给
Thread
类的构造函数,然后调用start()
方法启动线程。 示例代码:
- 定义一个类实现
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("This is a thread created by implementing Runnable interface.");
}
}
public class Main {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
通过线程池管理多线程提高系统性能和与多核处理器的适配性
- 使用线程池的优势:
- 降低资源消耗:避免频繁创建和销毁线程带来的开销。
- 提高响应速度:当任务到达时,无需等待线程创建即可执行。
- 提高线程的可管理性:可以对线程进行统一的调度和监控。
- Java中的线程池实现:
- 使用
ExecutorService
接口和ThreadPoolExecutor
类:ThreadPoolExecutor
是ExecutorService
接口的实现类,通过它可以创建自定义参数的线程池。 构造函数参数:- corePoolSize:线程池中核心线程的数量,即使线程处于空闲状态,也不会被销毁,除非设置了
allowCoreThreadTimeOut
为true
。 - maximumPoolSize:线程池中允许的最大线程数量。
- keepAliveTime:当线程数大于核心线程数时,多余的空闲线程等待新任务的最长时间,超过这个时间,多余线程将被销毁。
- unit:
keepAliveTime
的时间单位。 - workQueue:用于存储等待执行任务的队列。 示例代码:
- corePoolSize:线程池中核心线程的数量,即使线程处于空闲状态,也不会被销毁,除非设置了
- 使用
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) {
// 创建线程池
ExecutorService executorService = new ThreadPoolExecutor(
2,
4,
10,
TimeUnit.SECONDS,
new java.util.concurrent.LinkedBlockingQueue<>());
for (int i = 0; i < 10; i++) {
int taskNumber = i;
executorService.submit(() -> {
System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("Pool did not terminate");
}
}
} catch (InterruptedException ie) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
- **使用`Executors`工具类创建常见类型的线程池**:
- **`Executors.newFixedThreadPool(int nThreads)`**:创建一个固定大小的线程池,线程池中的线程数量始终保持为`nThreads`。适用于负载比较稳定,需要控制并发数的场景。
- **`Executors.newCachedThreadPool()`**:创建一个可缓存的线程池,如果线程池中的线程空闲时间超过60秒,线程将被回收。适用于任务执行时间短,并发量变化大的场景。
- **`Executors.newSingleThreadExecutor()`**:创建一个单线程的线程池,所有任务按照提交顺序依次执行。适用于需要保证顺序执行,并且资源有限的场景。
示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
// 创建固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
int taskNumber = i;
fixedThreadPool.submit(() -> {
System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
fixedThreadPool.shutdown();
// 创建可缓存线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
int taskNumber = i;
cachedThreadPool.submit(() -> {
System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
cachedThreadPool.shutdown();
// 创建单线程线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
int taskNumber = i;
singleThreadExecutor.submit(() -> {
System.out.println("Task " + taskNumber + " is running on thread " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
singleThreadExecutor.shutdown();
}
}
- 与多核处理器的适配:
- 根据处理器核心数动态调整线程池参数,例如核心线程数可以设置为处理器核心数,以充分利用多核处理器的计算能力。
- 通过合理设置线程池的最大线程数和队列容量,避免过多线程竞争资源导致性能下降,确保每个核心都能高效处理任务。