2023年经营惨淡,经历了裁员就业跳槽再就业,在找工作过程中对于知识的梳理和总结,本文总结JAVA多线程。
需要同时执行多个任务或处理大量并发请求时,
目前常用的场景有:
1、implements Runnable | extends Thread
2、ExecutorService实现类ThreadPoolExecutor
3、Executors.newFixedThreadPool
示例1:SimpleWebServer-模拟web服务器通过使用多线程可以同时处理多个请求
package xyz.lijiantao.study.thread;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Description 在Web服务器中,每个请求通常都是一个独立的任务,通过使用多线程可以同时处理多个请求,提高服务器的吞吐量和响应速度。
* @Date 2023/7/26 14:05
* @Created by LIJIANTAO
*/
public class SimpleWebServer {
public static void main(String[] args) {
final int port = 8080;
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("Web server is listening on port " + port);
while (true) {
Socket clientSocket = serverSocket.accept();
System.out.println("New client connected: " + clientSocket.getInetAddress());
// 创建新线程处理客户端请求
Thread requestHandlerThread = new Thread(new RequestHandler(clientSocket));
requestHandlerThread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
static class RequestHandler implements Runnable {
private final Socket clientSocket;
public RequestHandler(Socket clientSocket) {
this.clientSocket = clientSocket;
}
public void run() {
try (BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true)) {
// 从客户端读取请求内容
String request = in.readLine();
System.out.println("Received request from client: " + request);
// 模拟处理请求的耗时任务
Thread.sleep(2000);
// 返回响应给客户端
out.println("HTTP/1.1 200 OK");
out.println("Content-Type: text/html");
out.println();
out.println("");
out.println("Hello, Web Server!
");
out.println("");
clientSocket.close();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
}
示例2:MonitorThreadDealEfficient-模拟多线程VS单线程处理任务效率
package xyz.lijiantao.study.thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* @Description 模拟多线程处理任务
* @Date 2023/7/26 10:44
* @Created by LIJIANTAO
*/
public class MonitorThreadDealEfficient {
public static void main(String[] args) throws InterruptedException {
// 创建ThreadPoolExecutor线程池
int corePoolSize = 30; // 核心线程数,表示线程池中保持活动状态的线程数量
int maxPoolSize = 50; // 最大线程数,表示线程池允许创建的最大线程数量
long keepAliveTime = 5; // 线程空闲时间,超过该时间未执行任务的线程将被回收
TimeUnit timeUnit = TimeUnit.SECONDS; // 空闲时间单位
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
corePoolSize, maxPoolSize, keepAliveTime, timeUnit,
new LinkedBlockingQueue<>() // 任务队列,使用无界队列LinkedBlockingQueue
);
final CountDownLatch latch = new CountDownLatch(corePoolSize);
long start = System.currentTimeMillis();
for (int i = 0; i < 1000 * 10; i++) {
Task task = new Task(i,"multiThread");
threadPoolExecutor.submit(task);
}
// 等待所有线程执行完成
while (true){
// 判断是否还有正在执行的任务
if (threadPoolExecutor.getActiveCount() > 0) {
// System.out.println("There are still active tasks.");
} else {
System.out.println("No active tasks.");
long end = System.currentTimeMillis();
System.out.println("multiThread 执行花费时间: " + (end - start) / 1000 + "s");
// 关闭线程池
threadPoolExecutor.shutdown();
break;
}
}
long start1 = System.currentTimeMillis();
for (int i = 0; i < 1000 * 10; i++) {
Task task1 = new Task(i);
task1.run();
}
long end1 = System.currentTimeMillis();
System.out.println("single thread 执行花费时间: " + (end1 - start1) / 1000 + "s");
}
static class Task implements Runnable{
private int executeNum;
private CountDownLatch latch;
private String executeType = "single thread";
public Task(int executeNum,CountDownLatch latch){
this.executeNum = executeNum;
this.latch = latch;
}
public Task(int executeNum){
this.executeNum = executeNum;
}
public Task(int executeNum,String executeType){
this.executeNum = executeNum;
this.executeType = executeType;
}
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
finally {
// System.out.println(executeType +" Task executed times: " + (executeNum + 1) + " is running on thread " + Thread.currentThread().getName());
}
}
}
}
示例3:ParallelProcessingExample-多线程并行处理示例代码
package xyz.lijiantao.study.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* @Description java多线程并行处理示例代码
* @Date 2023/7/26 14:26
* @Created by LIJIANTAO
*/
public class ParallelProcessingExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
int numThreads = 4; // 假设有4个线程并行处理任务
int numTasks = 10; // 假设有10个任务
// 创建线程池,用于并行处理任务
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
// 创建任务列表和结果列表
List> tasks = new ArrayList<>();
List> results;
// 创建任务并添加到任务列表
for (int i = 0; i < numTasks; i++) {
final int taskId = i;
tasks.add(() -> {
// 模拟处理任务的耗时
Thread.sleep(1000);
return "Task " + taskId + " is completed by " + Thread.currentThread().getName();
});
}
// 并行处理任务并获取结果
results = executor.invokeAll(tasks);
// 关闭线程池
executor.shutdown();
// 打印任务执行结果
for (int i = 0; i < numTasks; i++) {
Future result = results.get(i);
System.out.println(result.get());
}
}
}
1、ThreadPoolExecutor VS ThreadPool
在Java中都是用于管理线程池的类,但它们之间存在一些区别:
ThreadPoolExecutor是Java标准库中的一个具体类,它实现了ExecutorService接口,用于管理线程池。ThreadPoolExecutor提供了丰富的线程池配置选项和管理方法,可以更加灵活地定制线程池的行为。
ThreadPool并不是Java标准库中的类,它可能是您自己实现的一个类或者某个第三方库提供的一个类。ThreadPool可能是基于ThreadPoolExecutor实现的,也可能是其他方式实现的。由于不是标准库中的类,ThreadPool可能不提供和ThreadPoolExecutor一样的配置选项和管理方法。
ThreadPoolExecutor提供了丰富的配置选项,可以根据需要配置核心线程数、最大线程数、线程空闲时间、任务队列类型、拒绝策略等。这使得您可以根据具体应用场景和资源需求来定制线程池的行为。
ThreadPool可能只提供了一组简单的配置选项,可能不如ThreadPoolExecutor灵活,适用性可能相对较差。
由于ThreadPoolExecutor是Java标准库的一部分,它是标准和通用的线程池实现。它可以直接在Java应用中使用,并且由于是标准库的一部分,未来的Java版本也会继续支持。
ThreadPool的实现可能是特定于某个库或项目的,如果使用第三方库提供的ThreadPool,则需要确保其可靠性和可维护性。
综上所述,ThreadPoolExecutor是Java标准库中用于管理线程池的标准实现,提供了丰富的配置选项和管理方法,可以在Java应用中直接使用。而ThreadPool可能是自定义的线程池实现或者某个第三方库提供的线程池实现,需要根据具体情况进行选择。一般情况下,优先考虑使用标准库中的ThreadPoolExecutor,以便获得更好的可扩展性和维护性。
2、Callable VS Runable
返回值: Callable
接口的call()
方法可以返回一个结果,而Runnable
接口的run()
方法没有返回值。
异常抛出: call()
方法声明了可能抛出Exception
异常,而run()
方法没有声明抛出任何异常。
使用方式: 在多线程编程中,Runnable
一般用于执行无返回值的任务,而Callable
用于执行有返回值的任务
执行方式: 在Java中,Runnable
通常通过Thread
类的构造函数传递给线程对象,并通过start()
方法来启动线程。
而Callable
通常通过ExecutorService
的submit()
方法提交给线程池来执行,并通过Future
对象获取返回结果。
你只管努力,剩下的交给时间。加油,打工人!
文本完