(1)List 接口 - 元素有序,允许存储重复元素,可通过索引访问元素。
主要实现类:
ArrayList:基于动态数组实现,查询快(随机访问 O(1)),增删慢(尤其是中间位置,O(n))。
非线程安全,适合查询多、增删少的场景。
LinkedList:基于双向链表实现,增删快(O(1),前提是知道节点位置),查询慢(O(n))。非线程安全。适合频繁增删的场景。
Vector:与 ArrayList 类似,但线程安全(方法用 synchronized 修饰),性能较低,不常用。
(2)Set 接口 - 无序、唯一
不允许存储重复元素(通过 equals() 和 hashCode() 判断)。无索引,不能通过下标访问。
主要实现类:
HashSet:基于 HashMap 实现。无序(不保证顺序)。查询、增删效率高(接近 O(1))。非线程安全。(其实就是
Set<String> studentNames = new HashSet<>();
studentNames.add("张三");)
LinkedHashSet:HashSet 的子类,内部使用链表维护插入顺序。有序(按插入顺序),性能略低于 HashSet。
(3)Map
存储 key-value 对。key 不允许重复(唯一),value 可以重复。通过 key 查找 value。
主要实现类:
HashMap:基于哈希表(数组 + 链表/红黑树)实现。无序。非线程安全。JDK 8 后,当链表长度 > 8 且数组长度 >= 64 时,链表转为红黑树,提高查找效率。
ConcurrentHashMap 本质上是一个HashMap,因此功能和HashMap一样,但是
ConcurrentHashMap 在 HashMap的基础上,提供了并发安全的实现。
典型使用场景:
场景举例:在 Web 应用中缓存用户信息、配置数据、热点商品信息等。
热点商品缓存示例(读多写少):
// 获取商品信息(高并发读),写请求:极少,只锁对应桶,不影响读。
Hashtable:早期的线程安全 Map 实现。不允许 null key 或 null value。
最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而
LinkedList 的底层数据结构是数据链表,不支持随机访问。
当哈希冲突发生时,HashMap使用链地址法来处理冲突。
定义:线程是进程中的一个执行单元,是 CPU 调度和执行的基本单位。一个进程可以包含多个线程。
类比:
进程 (Process):想象一个公司。它拥有独立的办公场所(内存空间)、资源(打印机、文件柜)和营业执照(独立的地址空间)。
线程 (Thread):公司里的员工。多个员工(线程)共享公司的资源(内存、文件句柄等),但他们可以同时工作(并发执行不同的任务)。
进程是操作系统分配资源的最小单元,线程是系统任务调度的最小单元。一个程序至少有一个进程,一个进程至少有一个线程。
创建线程要花费昂贵的资源和时间,当任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候
就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。
一个程序在同一时刻只有一条执行路径(一个线程)在运行。
特点:
简单:编程模型简单,逻辑清晰,无需考虑并发、同步、死锁等问题。
顺序执行:任务必须一个接一个地完成。如果一个任务耗时很长(如网络请求、文件读写、复杂计算),整个程序就会“卡住”,无法响应其他操作。
资源利用率低:在等待 I/O 操作(如读磁盘、等网络响应)时,CPU 处于空闲状态,无法利用起来处理其他任务。
典型应用:
简单的命令行工具。
早期的 GUI 应用(容易卡顿)。
对性能和并发要求不高的脚本。
例子:你用一个单线程程序下载文件。在下载过程中,程序界面完全无法操作,直到下载完成。
定义:一个程序在同一时间内创建并运行多个线程,这些线程可以并发(或并行)执行不同的任务。
目的:
提高性能和响应性:将耗时的任务(如 I/O、计算)放到后台线程执行,主线程(如 GUI 线程)可以保持对用户操作的响应。
充分利用多核 CPU:现代 CPU 通常是多核的。多线程可以让不同的线程在不同的 CPU 核心上真正并行执行,最大化 CPU 利用率。
模拟并发行为:如服务器需要同时处理成百上千个客户端请求。
特点:
并发性:多个线程看起来是“同时”运行的(在单核 CPU 上通过时间片轮转实现)。
并行性:在多核 CPU 上,多个线程可以真正在不同核心上同时运行。
复杂性:引入了线程安全、死锁、竞态条件、上下文切换开销等复杂问题。
什么是死锁:死锁 (Deadlock):两个或多个线程互相等待对方释放锁,导致所有线程都无法继续执行。
直接创建线程(new Thread().start())虽然简单,但在高并发场景下有严重问题:
创建/销毁开销大:频繁创建和销毁线程本身就很耗时。
资源耗尽:无限制地创建线程会耗尽系统资源(内存、CPU),导致系统崩溃或性能急剧下降。
缺乏管理:难以控制并发线程的数量,无法复用线程。
定义:线程池是一种管理线程的机制。它预先创建一组可重用的线程(“池子”),并将需要执行的任务提交给这个池。池中的线程会循环地从任务队列中取出任务并执行,执行完后不销毁,而是等待下一个任务。
核心组件:
线程池 (ThreadPool):管理线程集合。
工作线程 (Worker Thread):池中实际执行任务的线程。
任务队列 (Task Queue / Blocking Queue):存放待执行任务的队列。当所有工作线程都在忙时,新任务会进入队列等待。
拒绝策略 (Rejected Execution Handler):当任务队列也满了,且线程数达到上限时,如何处理新提交的任务(如抛异常、丢弃、调用者线程执行等)。
高并发的服务器应用(Web 服务器、数据库连接池)。
需要执行大量异步任务的程序。
任何需要避免频繁创建线程的场景。
方式一:继承 Thread 类,通过创建 Thread 类的子类,并重写其 run() 方法来创建线程。
方式二:实现 Runnable 接口,创建一个类实现 Runnable 接口,并实现其 run() 方法。
方式三:实现 Callable 接口 。生产环境、高并发、大量异步任务。
方式四:使用线程池。
在实际开发中,优先使用线程池 (ExecutorService) 配合 Runnable 或 Callable创建线程。
一、 使用 Executors 工厂类
1.Executors.newFixedThreadPool创建一个固定大小的线程池。创建一个固定大小的线程池。负载比较重、任务执行时间较长且稳定的场景。可以有效控制并发线程数。
2. Executors.newCachedThreadPool()创建一个可缓存的线程池。线程池大小不固定,线程可以按需创建。适用场景:执行大量短期异步任务的程序。
3. Executors.newSingleThreadExecutor()创建一个单线程的线程池。适用场景:需要保证任务按顺序执行,并且希望线程在意外终止后能自动恢复的场景。相当于一个“守护”线程。
二、 使用 ThreadPoolExecutor 构造函数创建线程池但阿里《Java开发手册》等规范建议避免使用它创建线程池,因为它隐藏了一些关键配置(如队列类型),容易导致风险(如无界队列)。
务必使用有界队列(如 ArrayBlockingQueue)来防止内存溢出。
同步,使用原子类,实现并发锁,使用 volatile 关键字,使用线程安全类。
线程被创建后并不会立即执行,而是需要调用start()方法来启动线程。当调用start()方法后,线程会进入就绪状态,等待CPU分配时间片。
一旦获得就会开始执行其run()方法中的代码。
使用 start() 方法会启动一个新的线程,并且新线程会运行 run() 方法中的代码。
直接调用 run() 方法不会启动新的线程,只是在当前线程中执行 run() 方法中的代码。
线程堵塞
这种情况通常发生在多线程环境中,比如等待I/O操作完成、等待锁释放、等待条件变量等。
StringBuffer是线程安全的,因为它的大部分方法都是同步的,可以在多线程环境下安全使用。
而StringBuilder不是线程安全的,它没有同步机制,因此在多线程环境下会导致数据不一致的问题。
https://cloud.tencent.com/developer/article/1677833
从Java 8开始,接口可以包含默认方法和静态方法,这些方法仍然是抽象的。
在Java中,子类通过extends关键字来继承抽象类,一个类只能继承一个抽象类,但可以实现多个接口。
反射是一种强大的工具,允许程序在运行时检查和修改其自身结构。反射的主要用途包括:
1动态创建对象2访问私有成员变量3获取类信息
通过反射创建对象有几种方式
1.使用Class对象的newInstance()方法
2.使用Constructor对象的newInstance()方法
3.通过ObjectInputStream的readObject方法实现反序列化
Spring Boot 是一个基于Java的框架,它简化了基于Spring的应用程序的初始设置和开发过程。
实现了自动配置,无需进行复杂的XML配置即可快速进行开发工作。它通过注解的方式自动配置Bean。
提供了许多“起步依赖”,预先配置好的一组依赖项,可以快速开始项目。
Spring Boot遵循“约定优于配置”的原则。
Spring Boot支持内嵌的Tomcat服务器。
提供命令行工具,使用脚本编写和运行Spring应用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。