背景:

2023年经营惨淡,经历了裁员就业跳槽再就业,在找工作过程中对于知识的梳理和总结,本文总结JAVA多线程。

应用场景:

需要同时执行多个任务或处理大量并发请求时

目前常用的场景有:

  • Web服务器: 在Web服务器中,每个请求通常都是一个独立的任务,通过使用多线程可以同时处理多个请求,提高服务器的吞吐量和响应速度。
  • 并行计算: 对于需要处理大量计算的任务,如图像处理、数据分析、科学计算等,可以使用多线程并行处理,充分利用多核处理器的性能优势,加快计算速度。
  • 数据爬虫: 网络爬虫通常需要同时处理多个网页的下载和解析。使用多线程可以并发地下载和解析多个网页,提高爬取效率。
  • 实时数据处理: 对于实时数据处理应用,如实时监控、实时日志处理等,可以使用多线程实时处理和响应事件。
  • 游戏开发: 在游戏开发中,多线程可以用于实现游戏逻辑和渲染的并行处理,提高游戏性能和流畅度。
  • 并发容器: Java提供了线程安全的并发容器,如ConcurrentHashMap、ConcurrentLinkedQueue等,适用于多线程环境下的高并发数据存储和访问。
  • 异步编程: 使用多线程可以实现异步编程,将耗时的任务放到后台执行,保持界面的响应性,提高用户体验。
  • 定时任务: 使用多线程可以实现定时任务的执行,定期执行一些需要周期性处理的任务。
  • 线程池: 使用线程池可以有效地管理和复用线程资源,避免频繁创建和销毁线程,提高性能和资源利用率。

创建方法:

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("<html><body>");
out.println("<h1>Hello, Web Server!</h1>");
out.println("</body></html>"); 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<Callable<String>> tasks = new ArrayList<>();
List<Future<String>> 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<String> result = results.get(i);
System.out.println(result.get());
}
}
}

常见的框架:

  • Executor框架: Executor框架是Java标准库中提供的多线程框架,通过Executors工具类可以创建不同类型的线程池,如FixedThreadPool、CachedThreadPool、SingleThreadPool等。Executor框架提供了高级的任务执行和管理功能,适用于大部分简单的多线程任务。
  • Fork/Join框架: Fork/Join框架是Java标准库中提供的用于并行计算的框架。它适用于大规模的任务划分和处理,并且可以利用多核处理器的优势来提高计算性能。
  • Akka: Akka是一个开源的、基于Actor模型的并发框架。它提供了高级的并发抽象,可以让开发者更容易地编写并发、分布式和容错的应用程序。Akka是用Scala编写的,但也支持Java。
  • RxJava: RxJava是ReactiveX的Java实现,它是一个异步编程库,支持响应式编程范式。RxJava可以帮助您处理异步任务、事件流和并发问题,提供了强大的工具来处理数据流和事件序列。
  • Quasar: Quasar是一个基于Fiber(纤程)的并发框架,它可以让您使用更轻量级的线程(纤程)来实现并发任务。Quasar提供了对Java并发原语的增强,使得编写高效且易于维护的并发代码更加容易。

其他知识点:

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

  1. 返回值: Callable接口的call()方法可以返回一个结果,而Runnable接口的run()方法没有返回值。

  2. 异常抛出: call()方法声明了可能抛出Exception异常,而run()方法没有声明抛出任何异常。

  3. 使用方式: 在多线程编程中,Runnable一般用于执行无返回值的任务,而Callable用于执行有返回值的任务

  4. 执行方式: 在Java中,Runnable通常通过Thread类的构造函数传递给线程对象,并通过start()方法来启动线程。

    Callable通常通过ExecutorServicesubmit()方法提交给线程池来执行,并通过Future对象获取返回结果。

总结:

你只管努力,剩下的交给时间。加油,打工人!

文本完

最全面的JAVA多线程知识总结的更多相关文章

  1. 最全面的Java多线程用法解析

    1.创建线程 在Java中创建线程有两种方法:使用Thread类和使用Runnable接口.在使用Runnable接口时需要建立一个Thread实例.因此,无论是通过Thread类还是Runnable ...

  2. JAVA多线程知识总结(二)

    本文是承接上一篇文章:JAVA多线程知识总结(一) 四.Java多线程的阻塞状态与线程控制  上文已经提到线程阻塞的集中具体类型.下面主要看引起JAVA线程阻塞的方法 1,join()-----让一个 ...

  3. 最强最全的Java后端知识体系

    目录 最全的Java后端知识体系 Java基础 算法和数据结构 Spring相关 数据库相关 方法论 工具清单 文档 @(最强最全的Java后端知识体系) 最全的Java后端知识体系 最全的Java后 ...

  4. JAVA 多线程知识总结(一)

    一,线程的生命周期以及五种基本状态 关于JAVA线程的生命周期,首先看一下下面这张图 上图中基本上囊括了Java中多线程各重要知识点.掌握了上图中的各知识点,Java中的多线程也就基本上掌握了. Ja ...

  5. 海纳百川而来的一篇相当全面的Java NIO教程

    目录 零.NIO包 一.Java NIO Channel通道 Channel的实现(Channel Implementations) Channel的基础示例(Basic Channel Exampl ...

  6. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

  7. 面试求职中需要了解的Java多线程知识

    Java中多线程的实现方式 在java的历史版本中,有两种创建多线程程序的方法 1) 通过创建Thread类的子类来实现(Thread类提供了主线程调用其它线程并行运行的机制) 主要步骤: 自定义类继 ...

  8. 031 一次全面的java复习

    一:相关概念 1.面向对象的三个特征 封装,继承,多态,这个应该是人人皆知,有时候也会加上抽象. 2.多态的好处 同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性.简单的说 ...

  9. 非常全面的java基础笔试题

    下面是java基础笔试题,当时我去笔试,做了1个小时(80道选择题,后面的简答题就没时间做了),结果很吓人,太挫了,最后被面试官忽悠去培训去了,呵呵.我偷偷把面试题弄了下来,用来学习吧,也希望能对你们 ...

  10. Java多线程知识整理

    多线程 1. 多线程基础 多线程状态转换图 普通方法介绍 yeild yeild,线程让步.是当前线程执行完后所有线程又统一回到同一起跑线.让自己或者其他线程运行,并不是单纯的让给其他线程. join ...

随机推荐

  1. S3 对象重命名

    本文所述操作适用于兼容 S3 协议的所有存储框架,包括 AWS S3.Aliyun OSS.MinIO.Ceph 等. 不知为何,截止目前,S3 协议并不包含对象重命名的接口.如果有重命名对象的需求, ...

  2. ES6之数组的Array.from()方法

    Array.from()方法就是构造函数本身的方法 将一个类数组对象或者可遍历对象转换成一个真正的数组. 那么什么是类数组对象呢?所谓类数组对象,最基本的要求就是具有length属性的对象. 1.将类 ...

  3. 沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟

    目录 沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置 沁恒 CH32V208(二): CH32V208的储存结构, 启动模式和时钟 CH32V 存储容量命 ...

  4. 工作中,我们经常用到哪些SQL语句呢?

    目录 一.DDL部分(create.drop.alter) 1.1 create 语句上 1.2 drop 语句 1.3 alter 语句 二.DML(数据操纵语言)和DQL(数据查询语言) 2.1 ...

  5. Pwn系列之Protostar靶场 Stack1题解

    (gdb) disasse main Dump of assembler code for function main: 0x08048464 <main+0>: push ebp 0x0 ...

  6. MySQL(Zip版)安装配置

    MySQL官网下载地址:MySQL 将压缩包内文件夹解压至任意目录,以mysql-5.7.40版本为例 第一步 添加环境变量 将mysql-5.7.40-winx64文件夹内的bin文件夹添加到环境变 ...

  7. 2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件。

    2023-03-01:用moonfdd/ffmpeg-go库,将h264文件编码为mp4文件. 答案2023-03-01: 使用 github.com/moonfdd/ffmpeg-go 库.现在我们 ...

  8. 2022-11-22:小美将要期中考试,有n道题,对于第i道题, 小美有pi的几率做对,获得ai的分值,还有(1-pi)的概率做错,得0分。 小美总分是每道题获得的分数。 小美不甘于此,决定突击复习,

    2022-11-22:小美将要期中考试,有n道题,对于第i道题, 小美有pi的几率做对,获得ai的分值,还有(1-pi)的概率做错,得0分. 小美总分是每道题获得的分数. 小美不甘于此,决定突击复习, ...

  9. 2021-10-24:快乐数。编写一个算法来判断一个数 n 是不是快乐数。「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是

    2021-10-24:快乐数.编写一个算法来判断一个数 n 是不是快乐数.「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和.然后重复这个过程直到这个数变为 1,也可能是 ...

  10. Mysql- DDL/DML/DQL/DCL 数据库基本操作语句(持续更新中)

    Mysql基本语法 前言: 在测试项目中经常需要使用到简单的Mysql语句,但是不知道语句结构是什么,经常在百度查来查去: 以下就是总结Mysql常用的基础操作语句: 只需要执行从创建开始执行示例中的 ...