自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(127)
  • 收藏
  • 关注

原创 Java内存区域

初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是那个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的 GC 分代年龄等信息。这些信息存放在对象头中。Java 堆内存是否规整,则取决于 GC 收集器的算法是“标记-清除”,还是“标记-整理”(也称作“标记-压缩”),值得注意的是,“复制算法”内存也是规整的。所以,尽量避免多个字符串拼接,因为这样会重新创建新的对象。在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,

2024-01-21 23:07:49 901

原创 Session详解

Session是一种记录客户状态的机制,不同于Cookie的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。如果说Cookie机制是通过检查客户身上的"通行证"来确定客户身份的话,那么Session机制就是通过检查服务器上的"客户明细表"来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,

2024-01-21 23:04:43 887

原创 Cookei详解

Cookie意为“甜饼”,是由W3C组织提出,最早由Netscape社区发展的一种机制。目前Cookie已经成为标准,所有的主流浏览器如IE、Netscape、Firefox、Opera等都支持Cookie。由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie的工作原理。Cookie实际上是一小段的文本信息。

2024-01-21 23:03:17 746

原创 JSP详解

Servlet 是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。JSP本质上是Servlet 的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML分离开来。JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet更侧重于控制逻辑,

2024-01-21 23:00:53 820

原创 Servlet原理解析

Servlet是运行在服务端的Java小程序,是SUN公司提供一套规范用来处理客户端请求、响应给浏览器的动态资源。1.获取请求数据2.处理请求3.完成响应在Java Web 程序中, Servlet 主要负责接收用户请求 HttpServletRequest ,在 doGet() , doPost() 中做相应的处理,并将 HttpServletResponse 反馈给用户。Servlet 可以设置初始化参数,供 Servlet 内部使用。一个 Servlet 类只会有一个实例。

2024-01-21 22:59:11 848

原创 Java I/O 方式

NIO 最重要的地方是当一个连接建立后,不需要对应一个线程,这个连接会被注册到多路复用器上面,所以所有的连接只需要一个线程即可,当这个线程中的多路复用器进行轮询时,发现连接上有请求的话,才开启一个线程进行处理。Java IO 的方式通常分为阻塞的 BIO(Blocking IO)、同步非阻塞的 NIO(New IO) 和异步非阻塞的 AIO(Asynchronous IO)。发送给一个通道的所有数据都必须首先放到缓冲区中,同样地,从通道中读取的任何数据都要先读到缓冲区中。NIO 是同步非阻塞的。

2024-01-20 22:48:47 804

原创 Java AIO

对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行IO操作,IO操作本身是同步的。但是对AIO来说,则更加进了一步,它不是在 IO 准备好时再通知线程,而是在 IO 操作已经完成后,再给线程发出通知。虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。在客户端使用的通道是 AsynchronousSocketChannel,这个通道处理除了提供 open 静态工厂方法外,还提供了read() 和 write() 方法。

2024-01-20 22:46:49 352

原创 Java NIO

Acceptor主要任务就是构建handler ,在获取到和client相关的SocketChannel之后 ,绑定到相应的hanlder上,对应的SocketChannel有读写事件之后,基于reactor 分发,hanlder就可以处理了(所有的IO事件都绑定到selector上,有Reactor分发)。我们知道,在我们使用传统方法进行网络IO操作的时候,需要使用一个线程监听IO事件,当事件到达之后,创建一个线程去处理接收到的IO事件,这种模型需要创建大量的线程,会极大的浪费内存等资源。

2024-01-20 22:44:20 859

原创 Java网络操作

创建发送端的Socket对象:这一步如果成功,就说明连接已经建立成功了。没有公有的构造函数,只能通过静态方法来创建实例。将数据源和目的封装成数据包中,不需要建立连接;返回一个对应的Socket对象。调用Socket对象的发送方法发送数据包。调用Socket对象的接收方法接收数据。每个数据报的大小在限制在64k;建立连接,形成传输数据的通道;创建接收端的Socket对象。创建发送端Socket对象。创建接收端Socket对象。在连接中进行大数据量传输;因无连接,是不可靠协议;本文由博客一文多发平台。

2024-01-20 22:41:58 905

原创 Java对象操作

ArrayList 中存储数据的数组 elementData 是用 transient 修饰的,因为这个数组是动态扩展的,并不是所有的空间都被使用,因此就不需要所有的内容都被序列化。通过重写序列化和反序列化方法,使得可以只序列化数组中有内容的那部分数据。如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,这些场景都需要用到序列化。反序列化将在序列化过程中所生成的二进制字节流转换成数据结构或者对象的过程。本文由博客一文多发平台。

2024-01-20 22:40:11 348

原创 Java字符操作2

UTF-16be 中的 be 指的是 Big Endian,也就是大端。相应地也有 UTF-16le,le 指的是 Little Endian,也就是小端。String 可以看成一个字符序列,可以指定一个编码方式将它编码为字节序列,也可以指定一个编码方式将一个字节序列解码为 String。Java 的内存编码使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,可以指定缓冲区的大小,或者可使用默认的大小。但是在程序中操作的通常是字符形式的数据,因此需要提供对字符进行操作的方法。

2024-01-20 22:35:46 844

原创 Java字节操作

实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。OutputStream 流对象是一个抽象类,不能实例化。所以,我们要找一个具体的子类 :FileOutputStream。DataInputStream 装饰者提供了对更多数据类型进行输入的操作,比如 int、double 等基本类型。不同的系统针对不同的换行符号识别是不一样的?把该字节输出流对象引用指向这个文件。通知系统去释放跟该文件相关的资源。

2024-01-20 22:33:58 829

原创 Java磁盘操作

我们要想实现IO的操作,就必须知道硬盘上文件的表现形式。而Java就提供了一个类File供我们使用。File:用于表示文件和目录的信息,但是它不表示文件的内容。本文由博客一文多发平台。

2024-01-20 22:31:57 309

原创 Java I/O 概览

I/O(Input/Outpu) 即输入/输出。学术的说 I/O 是信息处理系统(计算机)与外界(人或信息处理系统)间的通信。如计算机,即 CPU 访问任何寄存器和 Cache 等封装以外的数据资源都可当成 I/O ,包括且不限于内存,磁盘,显卡。软件开发中的 I/O 则常指磁盘、网络 IO。如何完成一次IO5 种IO模型。

2024-01-18 22:59:15 346

原创 容器源码分析 - 并发容器

synchronized 只锁定当前。ConcurrentHashMap 在执行 size 操作时先尝试不加锁,如果连续两次不加锁操作得到的结果一致,那么可以认为这个结果是正确的。尝试次数使用 RETRIES_BEFORE_LOCK 定义,该值为 2,retries 初始值为 -1,因此尝试次数为 3。如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈。每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问度。

2024-01-16 22:44:21 336

原创 容器源码分析 - Map

removeEldestEntry() 默认为 false,如果需要让它为 true,需要继承 LinkedHashMap 并且覆盖这个方法的实现,这在实现 LRU 的缓存中特别有用,通过移除最近最久未使用的节点,从而保证缓存空间足够,并且缓存的数据都是热点数据。设 HashMap 的 table 长度为 M,需要存储的键值对数量为 N,如果哈希函数满足均匀性的要求,那么每条链表的长度大约为 N/M,因此平均查找次数的复杂度为 O(N/M)。在进行扩容时,需要把键值对重新放到对应的桶上。

2024-01-16 22:42:12 373

原创 容器源码分析 - List

结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化。需要调用 System.arraycopy() 将 index+1 后面的元素都向左移动一位,该操作的时间复杂度为 O(N),可以看出 ArrayList 删除元素的代价是非常高的。把原数组整个复制到新数组中,这个操作代价很高,因此最好在创建 ArrayList 对象时就指定大概的容量大小,减少扩容操作的次数。在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,

2024-01-16 22:40:47 283

原创 容器中的设计模式

Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。应该注意的是 asList() 的参数为泛型的变长参数,不能使用基本类型数组作为参数,只能使用相应的。java.util.Arrays#asList() 可以把数组类型转换为 List 类型。来遍历实现了 Iterable 接口的聚合对象。本文由博客一文多发平台。

2024-01-16 22:38:55 320

原创 Java容器概览

容器主要包括 Collection 和 Map 两种,Collection 存储着对象的集合,而 Map 存储着键值对(两个对象)的映射表。LinkedHashSet:具有 HashSet 的查找效率,且内部使用双向链表维护元素的插入顺序。LinkedList:基于双向链表实现,只能顺序访问,但是可以快速地在链表中间插入和删除元素。它是遗留类,不应该去使用它。PriorityQueue:基于堆结构实现,可以用它来实现优先队列。HashSet:基于哈希表实现,支持快速查找,但不支持有序性操作。

2024-01-16 22:37:21 314

原创 Java正则表达式

是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。其实就是一种规则。元字符说明任何字符\d数字。等价于[0-9]\w单词字符。等待雨[a-zA-Z_0-9]

2024-01-16 22:20:24 374

原创 Java 常见类 II

DateForamt:可以进行日期和字符串的格式化和解析,但是由于是抽象类,所以使用具体子类SimpleDateFormat。示例2:先获取一个数值,换行后,再获取一个字符串,会出现问题。BigDecimal类:不可变的、任意精度的有符号十进制数,可以解决数据丢失问题。结果和我们想的有一点点不一样,这是因为浮点数类型的数据存储和整数不一样导致的。以确定字符的类别(小写字母,数字,等等),并将字符从大写转换成小写,反之亦然。解决方案二:把所有的数据都先按照字符串获取,然后要什么,就进行相应的转换。

2024-01-16 22:17:44 353

原创 Java 常见类 I

我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。

2024-01-15 23:01:13 790

原创 Java注解

Annontation 是 Java5 开始引入的新特征,中文名称叫注解。注解是插入到代码中的一种注释或者说是一种元数据。这些注解信息可以在编译期使用编译工具进行处理,也可以在运行期使用 Java 反射机制进行处理。自定义注解类编写的一些规则:(1) Annotation型定义为@interface,所有的Annotation会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口(2)参数成员只能用public或默认(default)这两个访问权修饰。

2024-01-15 22:59:48 660

原创 Java泛型

Java 中的泛型是伪泛型。类型擦除就是Java泛型只能用于在编译期间的静态类型检查,然后编译器生成的代码会擦除相应的类型信息这样到了运行期间实际上JVM根本不知道泛型所代表的具体类型。这样做的目的是因为Java泛型是1.5之后才被引入的,为了保持向下兼容。对于这一点,如果阅读 Java 集合框架的源码,可以发现有些类其实并不支持泛型。//T转换成Object这意味着不管我们声明 Node还是Node,到了运行期间,JVM 统统视为Node。

2024-01-15 22:57:30 817

原创 Java反射

反射相当于一系列解释操作,通知 Java 虚拟机要做什么,性能比直接的 Java 要慢很多。包括 private 和 protected 的成员,但不包括父类成员。利用反射访问私有属性:使用 setAccessible(true)本文由博客一文多发平台。

2024-01-15 22:55:07 315

原创 java异常

当发生异常情况时,一个代表该异常的对象被创建并且在导致该异常的方法中被抛出,而该方法可以选择自己处理异常或者传递该异常。同时,意味着Java程序的终止。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。因为,大多数Error异常属于永远不能被允许发生的状况,也属于合理的应用程序不该捕捉的异常。注意:非受检查异常为编译器不要求强制处理的异常,受检异常则是编译器要求必须处置的异常。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适的异常处理器。

2024-01-15 22:53:39 875

原创 final 和 static 关键字

private 方法隐式地被指定为 final,如果在子类中定义的方法和基类中的一个 private 方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序。只能访问所属类的静态字段和静态方法,方法中不能有 this 和 super 关键字。声明数据为常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。静态内部类不能访问外部类的非静态的变量和方法。

2024-01-15 22:51:56 347

原创 Object 通用方法

我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。

2024-01-15 22:50:13 761

原创 Java基本运算

的,因为 object 的 equals 方法是比较的对象的内存地址, 而 String 的 equals 方法比较的是对象的值。因此在方法中使指针引用其它对象,那么这两个指针此时指向的是完全不同的对象,在一方改变其所指向对象的内容时对另一方没有影响。如果在方法中改变对象的字段值会改变原对象该字段值,因为改变的是同一个地址指向的内容。中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。以下代码中 Dog dog 的 dog 是一个指针,存储的是对象的地址。那么还是用 if 比较合适。

2024-01-14 22:56:55 329

原创 Java数据类型

不适用于 Integer 对象,首先 i,j 进行自动拆箱,然后数值相加,得到数值 80,进行自动装箱后,和 m 引用相同的对象。Integer 对象无法与数值直接进行比较,自动拆箱后转为数值 80,显然 80 == 80,输出 true。编译器会在自动装箱过程调用 valueOf() 方法,因此多个 Integer 实例使用自动装箱来创建并且值相同,那么就会引用相同的对象。基本类型与其对应的包装类型之间的赋值使用。中,如果在的话就直接返回缓存池的内容。本文由博客一文多发平台。在 Java 8 中,

2024-01-14 22:55:23 284

原创 并发编程必会知识点

线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。

2024-01-14 22:53:00 1583

原创 线程池

如果可以拆分,则将其拆分成一个 CPU 密集型任务和一个 IO 密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,当需求增加时,则可以添加新的线程,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化。创建单个工作线程来执行任务,如果某个线程异常,则会创建另一个线程来替代,能确保依照任务在队列中的顺序来串行执行。

2024-01-14 22:51:01 843

原创 并发编程

线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。对于以下代码,虽然 b 线程先启动,但是因为在 b 线程中调用了 a 线程的 join() 方法,b 线程会等待 a 线程结束才继续执行,因此最后能够保证 a 线程的输出先于 b 线程的输出。调用 wait() 使得线程等待某个条件满足,线程在等待时会被挂起,当其他线程的运行使得这个条件满足时,其它线程会调用 notify() 或者 notifyAll() 来唤醒挂起的线程。

2024-01-07 22:23:44 1725

原创 线程池

如果可以拆分,则将其拆分成一个 CPU 密集型任务和一个 IO 密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,当需求增加时,则可以添加新的线程,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化。创建单个工作线程来执行任务,如果某个线程异常,则会创建另一个线程来替代,能确保依照任务在队列中的顺序来串行执行。

2024-01-07 22:21:52 767

原创 线程池

如果可以拆分,则将其拆分成一个 CPU 密集型任务和一个 IO 密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,当需求增加时,则可以添加新的线程,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化。创建单个工作线程来执行任务,如果某个线程异常,则会创建另一个线程来替代,能确保依照任务在队列中的顺序来串行执行。

2024-01-07 22:20:56 822

原创 线程池

如果可以拆分,则将其拆分成一个 CPU 密集型任务和一个 IO 密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,当需求增加时,则可以添加新的线程,每当提交一个任务时就创建一个线程,直到达到线程池的最大数量,这时线程池的规模将不再变化。创建单个工作线程来执行任务,如果某个线程异常,则会创建另一个线程来替代,能确保依照任务在队列中的顺序来串行执行。

2024-01-07 22:19:58 741

原创 并发容器

数据结构与HashMap 1.8 的结构类似,数组+链表 / 红黑二叉树(链表长度 > 8 时,转换为红黑树 )。尝试次数使用 RETRIES_BEFORE_LOCK 定义,该值为 2,retries 初始值为 -1,因此尝试次数为 3。(5)其余情况把新的 Node 节点按链表或红黑树的方式插入到合适位置,这个过程采用内置锁实现并发。CopyOnWriteArrayList 在写操作的同时允许读操作,大大提高了读操作的性能,很适合。, 从而使其并发度更高(并发度就是 Segment 的个数)。

2024-01-07 22:17:45 631

原创 原子操作类

通过 getIntVolatile(var1, var2) 得到旧的预期值,通过调用 compareAndSwapInt() 来进行 CAS 比较,如果该字段内存地址中的值等于 var5,那么就更新内存地址为 var1+var2 的变量为 var5+var4。可以看出,compareAndSet 方法的实际上也是先转换成 0,1 的整型变量,然后是通过针对 int 型变量的原子更新方法 compareAndSwapInt 来实现的。

2024-01-07 22:10:02 867

原创 Lock 体系

Condition 中有 awai()、signal()、signalAll() 方法,分别对应 Object 中放入 wait()、notify()、notifyAll() 方法,其实 Condition 也有上述三种方法,改变方法名称是为了避免使用上语义的混淆。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。,主要用来等待某种条件的发生,条件发生后,可以唤醒等待在该条件上的一个线程或者所有线程。

2024-01-07 22:04:45 786

原创 并发关键字

任意一个对象都拥有自己的 Monitor,当这个对象由同步块或者同步方法调用时, 执行方法的线程必须先获取该对象的 Monitor 才能进入同步块和同步方法, 如果没有获取到 Monitor 的线程将会被阻塞在同步块和同步方法的入口处,进入到 BLOCKED 状态。轻量级锁是由偏向锁升级而来,偏向锁运行在一个线程进入同步块的情况下,当第二个线程加入锁争用的时候,偏向锁就会升级为轻量级锁。当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

2024-01-07 21:46:58 767

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除