Java设计模式
This commit is contained in:
parent
e6d6fa7fd7
commit
dff4e5e84c
73
README.md
73
README.md
@ -1,20 +1,15 @@
|
|||||||
# :coffee: JAVA
|
# :coffee: JAVA
|
||||||
|
|
||||||
- Java 基础
|
+ [Java 反射与注解](notes/Java_反射与注解.md)
|
||||||
- GOF 23 种设计模式
|
+ [Java 并发编程](notes/Java_并发.md)
|
||||||
- 深入理解 Java 虚拟机
|
+ [Java 设计模式](notes/Java_设计模式.md)
|
||||||
- 网络编程原理
|
+ 深入理解 Java 虚拟机
|
||||||
- Netty 编程模式
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 💻 前端基础
|
## 💻 前端基础
|
||||||
|
|
||||||
- JavaScript 基础
|
- [JavaScript 基础](notes/JavaScript_基础.md)
|
||||||
- 原型与原型链,作用域与闭包,异步与单线程
|
|
||||||
- ECMAScript 6.0 基础
|
- ECMAScript 6.0 基础
|
||||||
- WebPack 基础
|
|
||||||
- Vue 核心概念
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -51,64 +46,32 @@
|
|||||||
+ [Linux 常用 Shell 命令](notes/Linux_常用Shell命令.md)
|
+ [Linux 常用 Shell 命令](notes/Linux_常用Shell命令.md)
|
||||||
+ [Docker 基础](notes/Docker_基础.md)
|
+ [Docker 基础](notes/Docker_基础.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 🌳 Spring 系列
|
|
||||||
|
|
||||||
### Spring
|
|
||||||
|
|
||||||
+ Spring事务机制、事务的传播与监控
|
|
||||||
|
|
||||||
### Spring Cloud
|
|
||||||
|
|
||||||
- Eureka 服务的注册和发现
|
|
||||||
- Eureka 高可用集群搭建
|
|
||||||
- Ribbon 客户端负载均衡,RestTemplate 服务远程调用
|
|
||||||
- OpenFeign 声明式服务调用,服务容错处理
|
|
||||||
- Hystix 服务容错保护,Hystrix Dashboard 断路器监控,Turbine 断路器聚合监控
|
|
||||||
- Zuul 网关服务
|
|
||||||
- Sleuth + Zipkin 服务链路追踪
|
|
||||||
- Config 分布式配置中心 ,集成 Bus 消息总线实现配置热更新
|
|
||||||
|
|
||||||
### 分布式解决方案
|
|
||||||
|
|
||||||
+ 全局 ID 生成方案
|
|
||||||
+ 分布式 Session 解决方案
|
|
||||||
+ 分布式锁解决方案
|
|
||||||
+ 分布式事务解决方案实战
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 常用技术栈
|
## 常用技术栈
|
||||||
|
|
||||||
### Kafka
|
### Kafka
|
||||||
|
|
||||||
1. [Kafka 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka简介.md)
|
+ [Kafka 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka简介.md)
|
||||||
2. [基于 Zookeeper 搭建 Kafka 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
|
+ [基于 Zookeeper 搭建 Kafka 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
|
||||||
3. [Kafka 生产者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka生产者详解.md)
|
+ [Kafka 生产者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka生产者详解.md)
|
||||||
4. [Kafka 消费者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka消费者详解.md)
|
+ [Kafka 消费者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka消费者详解.md)
|
||||||
5. [深入理解 Kafka 副本机制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka深入理解分区副本机制.md)
|
+ [深入理解 Kafka 副本机制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka深入理解分区副本机制.md)
|
||||||
|
|
||||||
### RabbitMQ
|
### RabbitMQ
|
||||||
|
|
||||||
- [RabbitMQ 核心概念](notes/RabbitMQ_基础.md)
|
+ [RabbitMQ 核心概念](notes/RabbitMQ_基础.md)
|
||||||
- [RabbitMQ 客户端开发](notes/RabbitMQ_客户端开发.md)
|
+ [RabbitMQ 客户端开发](notes/RabbitMQ_客户端开发.md)
|
||||||
- [基于 HAProxy + KeepAlived 搭建 RabbitMQ 高可用集群](notes/RabbitMQ_高可用集群架构.md)
|
+ [基于 HAProxy + KeepAlived 搭建 RabbitMQ 高可用集群](notes/RabbitMQ_高可用集群架构.md)
|
||||||
|
|
||||||
### ZooKeeper
|
### ZooKeeper
|
||||||
|
|
||||||
1. [ZooKeeper 简介及核心概念](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper简介及核心概念.md)
|
+ [ZooKeeper 简介及核心概念](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper简介及核心概念.md)
|
||||||
2. [ZooKeeper 单机环境和集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Zookeeper单机环境和集群环境搭建.md)
|
+ [ZooKeeper 单机环境和集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Zookeeper单机环境和集群环境搭建.md)
|
||||||
3. [ZooKeeper 常用 Shell 命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper常用Shell命令.md)
|
+ [ZooKeeper 常用 Shell 命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper常用Shell命令.md)
|
||||||
4. [ZooKeeper Java 客户端 —— Apache Curator](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_Java客户端Curator.md)
|
+ [ZooKeeper Java 客户端](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_Java客户端Curator.md)
|
||||||
5. [ZooKeeper ACL 权限控制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_ACL权限控制.md)
|
+ [ZooKeeper ACL 权限控制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_ACL权限控制.md)
|
||||||
|
|
||||||
### Nginx
|
### Nginx
|
||||||
|
|
||||||
- [Nginx 基础之静态网站部署,负载均衡,动静分离](notes/Nginx_基础.md)
|
- [Nginx 基础之静态网站部署,负载均衡,动静分离](notes/Nginx_基础.md)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 📊 算法
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
@ -1,612 +0,0 @@
|
|||||||
# 《Java 8 实战》读书笔记
|
|
||||||
## 目录<br/>
|
|
||||||
<a href="#第二部分-函数式数据处理">第二部分 函数式数据处理</a><br/>
|
|
||||||
<a href="#第4章-引入流">第4章 引入流</a><br/>
|
|
||||||
<a href="#1流的基本使用">1.流的基本使用</a><br/>
|
|
||||||
<a href="#2数值流">2.数值流</a><br/>
|
|
||||||
<a href="#3构建流">3.构建流</a><br/>
|
|
||||||
<a href="#第5章-使用流">第5章 使用流</a><br/>
|
|
||||||
<a href="#1中间操作和基本操作">1.中间操作和基本操作</a><br/>
|
|
||||||
<a href="#2flatMap的使用">2.flatMap的使用</a><br/>
|
|
||||||
<a href="#3归约">3.归约</a><br/>
|
|
||||||
<a href="#第6章-用流收集数据">第6章 用流收集数据</a><br/>
|
|
||||||
<a href="#1预定义收集器">1.预定义收集器</a><br/>
|
|
||||||
<a href="#第三部分-高效的Java-8编程">第三部分 高效的Java 8编程</a><br/>
|
|
||||||
<a href="#第12章-新的日期和时间API">第12章 新的日期和时间API</a><br/>
|
|
||||||
<a href="#121-LocalDate、LocalTime、Instant、Duration、period">12.1 LocalDate、LocalTime、Instant、Duration、period</a><br/>
|
|
||||||
<a href="#1使用-LocalDate-和-LocalTime">1.使用 LocalDate 和 LocalTime</a><br/>
|
|
||||||
<a href="#2使用LocalDateTime">2.使用LocalDateTime</a><br/>
|
|
||||||
<a href="#3时间间隔-Duration-或-Period">3.时间间隔 Duration 或 Period</a><br/>
|
|
||||||
<a href="#122-操纵、解析和格式化日期">12.2 操纵、解析和格式化日期</a><br/>
|
|
||||||
<a href="#1操纵日期加减">1.操纵日期加减</a><br/>
|
|
||||||
<a href="#2使用TemporalAdjusters">2.使用TemporalAdjusters</a><br/>
|
|
||||||
<a href="#3日期格式解析">3.日期格式解析</a><br/>
|
|
||||||
## 正文<br/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 第二部分 函数式数据处理
|
|
||||||
|
|
||||||
### 第4章 引入流
|
|
||||||
|
|
||||||
#### 1.流的基本使用
|
|
||||||
|
|
||||||
```java
|
|
||||||
// 基础数据类
|
|
||||||
public class Data {
|
|
||||||
|
|
||||||
public enum Type {MEAT, FISH, OTHER}
|
|
||||||
|
|
||||||
public static List<Dish> menu = Arrays.asList(
|
|
||||||
new Dish("pork", false, 800, Type.MEAT),
|
|
||||||
new Dish("beef", false, 700, Type.MEAT),
|
|
||||||
new Dish("chicken", false, 400, Type.MEAT),
|
|
||||||
new Dish("french fries", true, 530, Type.OTHER),
|
|
||||||
new Dish("rice", true, 350, Type.OTHER),
|
|
||||||
new Dish("season fruit", true, 120, Type.OTHER),
|
|
||||||
new Dish("pizza", true, 550, Type.OTHER),
|
|
||||||
new Dish("prawns", false, 300, Type.FISH),
|
|
||||||
new Dish("salmon", false, 450, Type.FISH));
|
|
||||||
|
|
||||||
static class Dish {
|
|
||||||
private final String name;
|
|
||||||
private final boolean vegetarian;
|
|
||||||
private final int calories;
|
|
||||||
private final Data.Type type;
|
|
||||||
|
|
||||||
public Dish(String name, boolean vegetarian, int calories, Data.Type type) {
|
|
||||||
this.name = name;
|
|
||||||
this.vegetarian = vegetarian;
|
|
||||||
this.calories = calories;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVegetarian() {
|
|
||||||
return vegetarian;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCalories() {
|
|
||||||
return calories;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Data.Type getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
```java
|
|
||||||
// 流的使用
|
|
||||||
public class Stream {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
List<String> collect = Data.menu.stream().filter(d -> d.getCalories() > 300).map(Data.Dish::getName).limit(3).collect(Collectors.toList());
|
|
||||||
collect.forEach(System.out::println);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2.数值流
|
|
||||||
|
|
||||||
**映射到数值流(mapToInt)**
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Stream {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
//得到的是 Stream<Integer>
|
|
||||||
java.util.stream.Stream<Integer> integerStream = Data.menu.stream().map(Data.Dish::getCalories);
|
|
||||||
Integer reduce = integerStream.reduce(0, Integer::sum);
|
|
||||||
System.out.println(reduce); //4200
|
|
||||||
|
|
||||||
//得到的是 IntStream
|
|
||||||
IntStream intStream = Data.menu.stream().mapToInt(Data.Dish::getCalories);
|
|
||||||
int sum = intStream.sum();
|
|
||||||
System.out.println(sum); //4200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**数值流到映射(boxed)**
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Stream {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
//得到的是 Stream<Integer>
|
|
||||||
java.util.stream.Stream<Integer> integerStream = Data.menu.stream().map(Data.Dish::getCalories);
|
|
||||||
Integer reduce = integerStream.reduce(0, Integer::sum);
|
|
||||||
System.out.println(reduce); //4200
|
|
||||||
|
|
||||||
//得到的是 IntStream
|
|
||||||
IntStream intStream = Data.menu.stream().mapToInt(Data.Dish::getCalories);
|
|
||||||
java.util.stream.Stream<Integer> boxed = intStream.boxed();
|
|
||||||
Integer reduceSum = boxed.reduce(0, Integer::sum);
|
|
||||||
System.out.println(reduceSum); //4200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```java
|
|
||||||
// 收集器对流的消耗
|
|
||||||
public class Stream {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
//得到的是 Stream<Integer>
|
|
||||||
java.util.stream.Stream<Integer> integerStream = Data.menu.stream().map(Data.Dish::getCalories);
|
|
||||||
Integer reduce = integerStream.reduce(0, Integer::sum);
|
|
||||||
System.out.println(reduce); //4200
|
|
||||||
|
|
||||||
//得到的是 IntStream
|
|
||||||
IntStream intStream = Data.menu.stream().mapToInt(Data.Dish::getCalories);
|
|
||||||
int sum = intStream.sum();
|
|
||||||
// 下面这行报错:IllegalStateException: stream has already been operated upon or closed
|
|
||||||
// 因为sum() 是一个终止流方法,会消耗掉流,所以调用 intStream.boxed() 方法时候会报错
|
|
||||||
java.util.stream.Stream<Integer> boxed = intStream.boxed();
|
|
||||||
Integer reduceSum = boxed.reduce(0, Integer::sum);
|
|
||||||
System.out.println(sum); //4200
|
|
||||||
System.out.println(reduceSum); //4200
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3.构建流
|
|
||||||
|
|
||||||
**1.由值创建流**
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class StreamCreate {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// 由值创建流
|
|
||||||
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
|
|
||||||
stream.map(String::toUpperCase).forEach(System.out::println);
|
|
||||||
|
|
||||||
// 创建空流
|
|
||||||
Stream<Object> empty = Stream.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**2.由数组创建流**
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class StreamCreate {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
int[] numbers = {2, 3, 5, 7, 11, 13};
|
|
||||||
int sum = Arrays.stream(numbers).sum();
|
|
||||||
System.out.println(sum); //41
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**3.由文件创建流**
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class StreamCreate {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
try (Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())) {
|
|
||||||
Set<String> collect = lines.flatMap(line -> Arrays.stream(line.split("")))
|
|
||||||
.distinct()
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
collect.forEach(System.out::print);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**4.由函数生成流**
|
|
||||||
|
|
||||||
Stream API提供了两个静态方法来从函数生成流: **Stream.iterate**和**Stream.generate**。这两个操作可以创建所谓的无限流:不像从固定集合创建的流那样有固定大小的流。由iterate和generate产生的流会用给定的函数按需创建值,因此可以无穷无尽地计算下去!一般来说,应该使用limit(n)来对这种流加以限制,以避免打印无穷多个值。
|
|
||||||
|
|
||||||
- **iterate**方法接受一个初始值(在这里是0),还有一个依次应用在每个产生的新值上的Lambda(UnaryOperator\<T>类型)。
|
|
||||||
- **generate**方法也可让你按需生成一个无限流。但generate不是依次对每个新生成的值应用函数的。它接受一个Supplier\<T>类型的Lambda提供新的值。
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class StreamCreate {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// 迭代
|
|
||||||
Stream.iterate(0, n -> n + 2)
|
|
||||||
.limit(10)
|
|
||||||
.forEach(System.out::println);
|
|
||||||
|
|
||||||
// 生成
|
|
||||||
Stream.generate(Math::random)
|
|
||||||
.limit(5)
|
|
||||||
.forEach(System.out::println);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 第5章 使用流
|
|
||||||
|
|
||||||
你可以把Java 8的流看作花哨又懒惰的数据集迭代器。它们支持两种类型的操作:中间操作和终端操作。中间操作可以链接起来,**将一个流转换为另一个流**。这些操作不会消耗流,其目的是建立一个流水线。与此相反,**终端操作会消耗流**,以产生一个最终结果,例如返回流中的最大元素。
|
|
||||||
|
|
||||||
#### 1.中间操作和基本操作
|
|
||||||
|
|
||||||
**表5-1 中间操作和终端操作**
|
|
||||||
|
|
||||||
| 操作 | 类型 | 返回类型 | 使用的类型/函数式接口 | 函数描述符 |
|
|
||||||
| --------- | ----------------- | ------------ | ---------------------- | --------------- |
|
|
||||||
| filter | 中间 | Stream<T> | Predicate\<T> | T -> boolean |
|
|
||||||
| distinct | 中间(有状态-无界) | Stream<T> | | |
|
|
||||||
| skin | 中间(有状态-有界) | Stream<T> | long | |
|
|
||||||
| limit | 中间(有状态-有界) | Stream<T> | long | |
|
|
||||||
| map | 中间 | Stream<T> | Function<T,R> | T -> R |
|
|
||||||
| flatMap | 中间 | Stream<T> | Function<T,Stream\<R>> | T -> Stream\<R> |
|
|
||||||
| sorted | 中间(有状态-无界) | Stream<T> | Comparator\<T> | (T , T) -> int |
|
|
||||||
| anyMatch | 终端 | boolean | Predicate\<T> | T -> boolean |
|
|
||||||
| noneMatch | 终端 | boolean | Predicate\<T> | T -> boolean |
|
|
||||||
| allMatch | 终端 | boolean | Predicate\<T> | T -> boolean |
|
|
||||||
| findAny | 终端 | Optional\<T> | | |
|
|
||||||
| findFirst | 终端 | Optional\<T> | | |
|
|
||||||
| forEach | 终端 | void | Cosumer\<T> | T -> void |
|
|
||||||
| collect | 终端 | R | collector<T, A, R> | |
|
|
||||||
| reduce | 终端 | Optional\<T> | BinaryOperator\<T> | (T , T) -> T |
|
|
||||||
| count | 终端 | long | | |
|
|
||||||
|
|
||||||
#### 2.flatMap的使用
|
|
||||||
|
|
||||||
给 定 单 词 列 表["Hello","World"],你想要返回列表["H","e","l", "o","W","r","d"]。
|
|
||||||
|
|
||||||
**Arrays.stream()的方法可以接受一个数组并产生一个流 。**
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Stream {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String[] strings = {"Hello", "World"};
|
|
||||||
|
|
||||||
// 如下图 5.5
|
|
||||||
List<String[]> list01 = Arrays.stream(strings)
|
|
||||||
.map(s -> s.split(""))
|
|
||||||
.distinct().collect(Collectors.toList());
|
|
||||||
|
|
||||||
// 使用flatMap方法的效果是,各个数组并不是分别映射成一个流,而是映射成流的内容。 如下图5.6
|
|
||||||
List<String> list02 = Arrays.stream(strings)
|
|
||||||
.map(s -> s.split(""))
|
|
||||||
.flatMap(Arrays::stream)
|
|
||||||
.distinct().collect(Collectors.toList());
|
|
||||||
|
|
||||||
//每个单词转换成一个字母数组,然后把每个数组变成了一个独立的流。
|
|
||||||
List<java.util.stream.Stream<String>> list03 = Arrays.stream(strings)
|
|
||||||
.map(s -> s.split(""))
|
|
||||||
.map(Arrays::stream)
|
|
||||||
.distinct().collect(Collectors.toList());
|
|
||||||
|
|
||||||
list01.forEach(System.out::println);
|
|
||||||
list02.forEach(System.out::println);
|
|
||||||
list03.forEach(System.out::println);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/flatmap1.png"/> </div></br>
|
|
||||||
|
|
||||||
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/flatmap2.png"/> </div></br>
|
|
||||||
|
|
||||||
#### 3.归约
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class Stream {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
|
|
||||||
Integer reduce = integers.stream().reduce(0, (a, b) -> a + b);
|
|
||||||
System.out.println(reduce);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 第6章 用流收集数据
|
|
||||||
|
|
||||||
#### 1.预定义收集器
|
|
||||||
|
|
||||||
预定义收集器主要指 Collectors类提供的工厂方法(例如groupingBy)创建的收集器。它们主要提供了三大功能:
|
|
||||||
|
|
||||||
- 将流元素归约和汇总为一个值
|
|
||||||
- 元素分组
|
|
||||||
- 元素分区
|
|
||||||
|
|
||||||
**表6.1 Collectors 类的静态工厂方法**
|
|
||||||
|
|
||||||
| 工厂方法 | 返回类型 | 用于 |
|
|
||||||
| ----------------- | --------------------- | ------------------------------------------------------------ |
|
|
||||||
| toList | List\<T> | 把流中所有项目收集到一个List |
|
|
||||||
| toSet | Set\<T> | 把流中所有项目收集到一个Set,删除重复项 |
|
|
||||||
| toCollection | Collection\<T> | 把流中所有项目收集到给定的供应源创建的集合 |
|
|
||||||
| counting | Long | 计算流中元素的个数 |
|
|
||||||
| summingInt | Integer | 对流中项目的一个整数属性求和 |
|
|
||||||
| averagingInt | Double | 计算流中项目Integer属性的平均值 |
|
|
||||||
| summarizingInt | IntSummaryStatistics | 收集关于流中项目Integer属性的统计值,例如最大、最小、总和与平均值 |
|
|
||||||
| joining | String | 连接对流中每个项目调用toString方法所生成的字符串 |
|
|
||||||
| maxBy | Optional\<T> | 查找最大元素的Optional,或如果流为空则为Optional.empty() |
|
|
||||||
| minBy | Optional\<T> | 查找最小元素的Optional,或如果流为空则为Optional.empty() |
|
|
||||||
| reducing | 规约操作产生的类型 | 从一个作为累加器的初始值开启,利用BinaryOperator与流中的元素逐个结合,从而将流归约为单个值 |
|
|
||||||
| collectingAndThen | 转换返回返回的类型 | 包裹另一个收集器,对其结果应用转换函数 |
|
|
||||||
| groupingBy | Map<K,List\<T>> | 根据项目的一个属性的值对流中项目作分组,并将其属性值作为结果Map的键 |
|
|
||||||
| partitionBy | Map<Boolean,List\<T>> | 根据对流中每个项目应用谓词的结果来对项目进行区分 |
|
|
||||||
|
|
||||||
```java
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import static java.util.stream.Collectors.*;
|
|
||||||
|
|
||||||
public class Stream {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// toList
|
|
||||||
List<Data.Dish> dishList = Data.menu.stream().collect(toList());
|
|
||||||
|
|
||||||
// toSet
|
|
||||||
Set<Data.Dish> dishSet = Data.menu.stream().collect(Collectors.toSet());
|
|
||||||
|
|
||||||
// toCollection
|
|
||||||
ArrayList<Data.Dish> arrayList = Data.menu.stream()
|
|
||||||
.collect(Collectors.toCollection(ArrayList::new));
|
|
||||||
|
|
||||||
// counting
|
|
||||||
long count = Data.menu.stream().count();
|
|
||||||
// summingInt 可以用中间操作等价
|
|
||||||
Integer sum01 = Data.menu.stream()
|
|
||||||
.collect(Collectors.summingInt(Data.Dish::getCalories));
|
|
||||||
Integer sum02 = Data.menu.stream()
|
|
||||||
.mapToInt(Data.Dish::getCalories).sum();
|
|
||||||
|
|
||||||
// averagingInt
|
|
||||||
Double average = Data.menu.stream()
|
|
||||||
.collect(Collectors.averagingInt(Data.Dish::getCalories));
|
|
||||||
|
|
||||||
// summarizingInt
|
|
||||||
IntSummaryStatistics statistics = Data.menu.stream()
|
|
||||||
.collect(Collectors.summarizingInt(Data.Dish::getCalories));
|
|
||||||
statistics.getAverage();
|
|
||||||
statistics.getMax();
|
|
||||||
|
|
||||||
// joining
|
|
||||||
String joining = Data.menu.stream().map(Data.Dish::getName)
|
|
||||||
.collect(Collectors.joining(","));
|
|
||||||
|
|
||||||
// maxBy
|
|
||||||
Optional<Data.Dish> max = Data.menu.stream()
|
|
||||||
.max(Comparator.comparingInt(Data.Dish::getCalories));
|
|
||||||
|
|
||||||
// minBy
|
|
||||||
Optional<Data.Dish> min = Data.menu.stream()
|
|
||||||
.min(Comparator.comparingInt(Data.Dish::getCalories));
|
|
||||||
|
|
||||||
// reducing
|
|
||||||
Integer reduce01 = Data.menu.stream().map(Data.Dish::getCalories)
|
|
||||||
.reduce(0, Integer::sum);
|
|
||||||
Integer reduce02 = Data.menu.stream().map(Data.Dish::getCalories)
|
|
||||||
.reduce(0, Integer::sum);
|
|
||||||
|
|
||||||
// collectingAndThen
|
|
||||||
Integer size = Data.menu.stream().collect(collectingAndThen(toList(), List::size));
|
|
||||||
|
|
||||||
// groupingBy
|
|
||||||
Map<Data.Type, List<Data.Dish>> typeListMap = Data.menu.stream()
|
|
||||||
.collect(groupingBy(Data.Dish::getType));
|
|
||||||
|
|
||||||
// partitionBy
|
|
||||||
Map<Boolean, List<Data.Dish>> booleanListMap = Data.menu.stream()
|
|
||||||
.collect(partitioningBy(Data.Dish::isVegetarian));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## 第三部分 高效的Java 8编程
|
|
||||||
|
|
||||||
### 第12章 新的日期和时间API
|
|
||||||
|
|
||||||
#### 12.1 LocalDate、LocalTime、Instant、Duration、period
|
|
||||||
|
|
||||||
##### 1.使用 LocalDate 和 LocalTime
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class NewDateApi {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// 创建日期
|
|
||||||
LocalDate date = LocalDate.of(2018, 10, 8);
|
|
||||||
int year = date.getYear(); // 2018
|
|
||||||
Month month = date.getMonth(); // OCTOBER
|
|
||||||
int value = month.getValue(); // 10
|
|
||||||
int dayOfMonth = date.getDayOfMonth(); // 8
|
|
||||||
int i = date.lengthOfMonth(); // 31
|
|
||||||
|
|
||||||
// 获取当前日期
|
|
||||||
LocalDate now = LocalDate.now();
|
|
||||||
|
|
||||||
//创建时间
|
|
||||||
LocalTime time = LocalTime.of(12, 13, 32);
|
|
||||||
int hour = time.getHour();
|
|
||||||
int minute = time.getMinute();
|
|
||||||
int second = time.getSecond();
|
|
||||||
|
|
||||||
// 通过解析创建日期和时间
|
|
||||||
// the text to parse such as "2007-12-03", not null
|
|
||||||
LocalDate localDate = LocalDate.parse("2019-03-12");
|
|
||||||
// the text to parse such as "10:15:30", not null
|
|
||||||
LocalTime localTime = LocalTime.parse("12:21:45");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
##### 2.使用LocalDateTime
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class NewDateApi {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
|
|
||||||
LocalTime time = LocalTime.of(13, 45, 20);
|
|
||||||
|
|
||||||
LocalDateTime dt1 = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45, 20);
|
|
||||||
|
|
||||||
LocalDateTime dt2 = LocalDateTime.of(date, time);
|
|
||||||
LocalDateTime dt3 = date.atTime(13, 45, 20);
|
|
||||||
LocalDateTime dt4 = date.atTime(time);
|
|
||||||
LocalDateTime dt5 = time.atDate(date);
|
|
||||||
|
|
||||||
LocalDate localDate = dt1.toLocalDate();
|
|
||||||
LocalTime localTime = dt1.toLocalTime();
|
|
||||||
|
|
||||||
boolean equal = dt1.isEqual(dt2); // true
|
|
||||||
boolean equals = date.equals(localDate); // true
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
##### 3.时间间隔 Duration 或 Period
|
|
||||||
|
|
||||||
```java
|
|
||||||
// 计算时间间隔
|
|
||||||
public class NewDateApi {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
LocalDate date01 = LocalDate.of(2014, Month.MARCH, 18);
|
|
||||||
LocalDate date02 = LocalDate.of(2012, Month.MARCH, 23);
|
|
||||||
LocalTime time01 = LocalTime.of(13, 45, 20);
|
|
||||||
LocalTime time02 = LocalTime.of(13, 12, 35);
|
|
||||||
|
|
||||||
// 计算日期间隔
|
|
||||||
Period between01 = Period.between(date01, date02);
|
|
||||||
|
|
||||||
// 计算时间间隔
|
|
||||||
Duration between02 = Duration.between(time01, time02);
|
|
||||||
|
|
||||||
// 间隔时间可能为正值 也可能为负值 可以用 isNegative 判断
|
|
||||||
System.out.println(between01.getDays());
|
|
||||||
System.out.println(between01.getYears());
|
|
||||||
System.out.println(between02.getSeconds());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```java
|
|
||||||
// 创建时间间隔
|
|
||||||
public class NewDateApi {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// 创建 Duration 和 Period 对象
|
|
||||||
Duration duration = Duration.ofMinutes(3);
|
|
||||||
Duration duration1 = Duration.of(3, ChronoUnit.MINUTES);
|
|
||||||
|
|
||||||
Period tenDays = Period.ofDays(10);
|
|
||||||
Period threeWeeks = Period.ofWeeks(3);
|
|
||||||
Period twoYearsSixMonthsOneDay = Period.of(2, 6, 1);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 12.2 操纵、解析和格式化日期
|
|
||||||
|
|
||||||
##### 1.操纵日期加减
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class NewDateApi {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// 以直接修改方式操作 LocalDate
|
|
||||||
LocalDate date1 = LocalDate.of(2014, 3, 18);
|
|
||||||
LocalDate date2 = date1.withYear(2011);
|
|
||||||
LocalDate date3 = date2.withDayOfMonth(25);
|
|
||||||
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 9);
|
|
||||||
|
|
||||||
// 以相对的方式操作 LocalDate
|
|
||||||
LocalDate date5 = date1.plusWeeks(1);
|
|
||||||
LocalDate date6 = date1.minusYears(3);
|
|
||||||
LocalDate date7 = date1.plus(6, ChronoUnit.MONTHS);
|
|
||||||
|
|
||||||
|
|
||||||
// 操作 LocalDate
|
|
||||||
LocalTime time = LocalTime.of(12, 3, 18);
|
|
||||||
LocalTime time1 = time.withHour(3);
|
|
||||||
LocalTime time2 = time.plus(3, ChronoUnit.HOURS);
|
|
||||||
System.out.println(time2.getHour());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
##### 2.使用TemporalAdjusters
|
|
||||||
|
|
||||||
```java
|
|
||||||
import java.time.*;
|
|
||||||
import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;
|
|
||||||
import static java.time.temporal.TemporalAdjusters.nextOrSame;
|
|
||||||
|
|
||||||
public class NewDateApi {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
LocalDate date1 = LocalDate.of(2014, 3, 18);
|
|
||||||
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
|
|
||||||
LocalDate date3 = date2.with(lastDayOfMonth());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/TemporalAdjuster类中的工厂方法.png"/> </div></br>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
##### 3.日期格式解析
|
|
||||||
|
|
||||||
```java
|
|
||||||
public class NewDateApi {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
// 使用内置格式解析
|
|
||||||
LocalDate date = LocalDate.of(2014, 3, 18);
|
|
||||||
String s1 = date.format(DateTimeFormatter.ISO_LOCAL_DATE); //2014-03-18
|
|
||||||
|
|
||||||
|
|
||||||
// 使用自定义格式解析
|
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
|
|
||||||
LocalDate date1 = LocalDate.of(2014, 3, 18);
|
|
||||||
String formattedDate = date1.format(formatter);
|
|
||||||
LocalDate date2 = LocalDate.parse(formattedDate, formatter);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,254 +0,0 @@
|
|||||||
# 《深入理解Java虚拟机》读书笔记
|
|
||||||
## 目录<br/>
|
|
||||||
<a href="#第二章-java内存区域与内存溢出异常">第二章 java内存区域与内存溢出异常</a><br/>
|
|
||||||
<a href="#22-运行时数据区域">2.2 运行时数据区域</a><br/>
|
|
||||||
<a href="#221--程序计数器">2.2.1 程序计数器</a><br/>
|
|
||||||
<a href="#222--Java虚拟机栈">2.2.2 Java虚拟机栈</a><br/>
|
|
||||||
<a href="#223-本地方法栈">2.2.3 本地方法栈</a><br/>
|
|
||||||
<a href="#224-Java堆">2.2.4 Java堆</a><br/>
|
|
||||||
<a href="#225-方法区">2.2.5 方法区</a><br/>
|
|
||||||
<a href="#第四章-虚拟机性能监控与故障处理工具">第四章 虚拟机性能监控与故障处理工具</a><br/>
|
|
||||||
<a href="#421-JDK命令行工具">4.2.1 JDK命令行工具</a><br/>
|
|
||||||
<a href="#421-jps虚拟机进程状况工具">4.2.1 jps:虚拟机进程状况工具 </a><br/>
|
|
||||||
<a href="#422-jstat虚拟机统计信息监视工具">4.2.2 jstat:虚拟机统计信息监视工具</a><br/>
|
|
||||||
<a href="#1-gc-参数返回结果">1. gc 参数返回结果</a><br/>
|
|
||||||
<a href="#2-class-参数返回结果">2. class 参数返回结果</a><br/>
|
|
||||||
<a href="#3-gcmetacapacity-参数返回结果">3. gcmetacapacity 参数返回结果</a><br/>
|
|
||||||
<a href="#423-jinfoJava配置信息工具">4.2.3 jinfo:Java配置信息工具</a><br/>
|
|
||||||
<a href="#424-jmapJava内存映像工具">4.2.4 jmap:Java内存映像工具 </a><br/>
|
|
||||||
<a href="#425-jhat虚拟机堆转储快照分析工具">4.2.5 jhat:虚拟机堆转储快照分析工具 </a><br/>
|
|
||||||
<a href="#426-jstackJava堆栈跟踪工具">4.2.6 jstack:Java堆栈跟踪工具 </a><br/>
|
|
||||||
<a href="#43-JDK的可视化工具">4.3 JDK的可视化工具 </a><br/>
|
|
||||||
<a href="#第十二章-Java内存模型">第十二章 Java内存模型</a><br/>
|
|
||||||
## 正文<br/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 第二章 java内存区域与内存溢出异常
|
|
||||||
|
|
||||||
### 2.2 运行时数据区域
|
|
||||||
|
|
||||||
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/java虚拟机运行时数据区.png"/> </div></br>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 2.2.1 程序计数器
|
|
||||||
|
|
||||||
**当前线程所执行的字节码的行号指示器。**
|
|
||||||
|
|
||||||
- 为了线程切换后能够恢复到正确地执行位置,每个线程都需要有一个独立的程序计数器;
|
|
||||||
- 如果正在执行java方法,计数器记录的是正在执行的虚拟机字节码指令的地址,如果执行的是Native方法,则计数器值为空;
|
|
||||||
- 此内存区域是唯一一个在java虚拟机规范中没有规定任何outOfMemoryError情况的区域。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 2.2.2 Java虚拟机栈
|
|
||||||
|
|
||||||
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出入口等信息。每一个方法从调用直到执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。
|
|
||||||
|
|
||||||
- 局部变量表存放了编译器可知的各种基本数据类型、对象引用和returnAddress类型(指向一条字节码指令的地址)。
|
|
||||||
- 在java虚拟机规范中,对这个区域规定了两种异常:
|
|
||||||
- 如果线程请求的栈深入大于虚拟机所允许的深度,将抛出StackOverflowError异常;
|
|
||||||
- 如果虚拟机栈扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 2.2.3 本地方法栈
|
|
||||||
|
|
||||||
与虚拟机栈类似,针对Native 方法服务。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 2.2.4 Java堆
|
|
||||||
|
|
||||||
此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java 堆可以处于物理上不连续的内存空间中,只要是逻辑上是连续的即可。如果堆中没有内存完成实例分配,并且堆也无法在扩展时,将会抛出OutOfMemoryError异常。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 2.2.5 方法区
|
|
||||||
|
|
||||||
方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
|
|
||||||
|
|
||||||
- 当方法区无法满足内存分配的需求时,将会抛出OutOfMemoryError异常。
|
|
||||||
- **运行时常量池**是方法区的一部分,Class文件中出了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存在。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 第四章 虚拟机性能监控与故障处理工具
|
|
||||||
|
|
||||||
部分内容参考自博客:[JDK的命令行工具](https://blog.csdn.net/qq_31156277/article/details/80035236)
|
|
||||||
|
|
||||||
### 4.2.1 JDK命令行工具
|
|
||||||
|
|
||||||
#### 4.2.1 jps:虚拟机进程状况工具
|
|
||||||
|
|
||||||
命令格式: jps \[options] [hostid]
|
|
||||||
|
|
||||||
| 参数 | 描述 |
|
|
||||||
| ---- | ------------------------------------------------ |
|
|
||||||
| -l | 输出主类的全名,如果是执行的jar,则输出jar的路径 |
|
|
||||||
| -v | 输出JVM启动时的JVM参数 |
|
|
||||||
| -m | 输出虚拟机进程启动时传递给主类main() 函数的参数 |
|
|
||||||
|
|
||||||
#### 4.2.2 jstat:虚拟机统计信息监视工具
|
|
||||||
|
|
||||||
命令格式:jstat [options] vmid [interval \[s|ms][count]] ]
|
|
||||||
|
|
||||||
命令格式:jstat \[-命令选项]\[vmid]\[间隔时间/毫秒][查询次数]
|
|
||||||
|
|
||||||
| 参数 | 功能作用 |
|
|
||||||
| ----------------- | ------------------------------------------------------------ |
|
|
||||||
| -class | 监视类装载、卸载数量,以及总空间和装载耗时等 |
|
|
||||||
| -gc | 监视堆中 eden、 survivor 、老年代、元空间等空间大小和已使用情况,GC次数、耗时等 |
|
|
||||||
| -gcmetacapacity | 元空间 |
|
|
||||||
| -gcutil | 与gc 类似,但是注重的是占比情况 |
|
|
||||||
| -printcompilation | 输出已经被JIT重新编译的方法 |
|
|
||||||
| -gcoldcapacity | 老年代统计信息 |
|
|
||||||
| -gcnew | 新生代 |
|
|
||||||
| -gccause | 与-gcutil相似,但是会输出上一次GC的原因 |
|
|
||||||
|
|
||||||
##### 1. gc 参数返回结果
|
|
||||||
|
|
||||||
使用-gc 命令; 为了能够更加直观,在程序中设置了VM相关参数; 然后运行、查看结果并分析。
|
|
||||||
|
|
||||||
| 参数 | 解析 |
|
|
||||||
| ---- | -------------------- |
|
|
||||||
| S0C | surivor(s0)区域大小 |
|
|
||||||
| s1c | s1区大小 |
|
|
||||||
| S0U | S0的使用大小 |
|
|
||||||
| S1U | S1的使用大小 |
|
|
||||||
| EC | eden可以使用的大小 |
|
|
||||||
| EU | eden已经使用 |
|
|
||||||
| OC | 老年代可以使用的大小 |
|
|
||||||
| OU | 老年代已经使用的带下 |
|
|
||||||
| MC | 元空间可以使用的大小 |
|
|
||||||
| MU | 元空间已经使用的大小 |
|
|
||||||
| CCSC | 压缩类空间大小 |
|
|
||||||
| CCSU | 压缩类已经使用大小 |
|
|
||||||
| YGC | 年轻代垃圾回收次数 |
|
|
||||||
| YGCT | 年轻代垃圾回收总耗时 |
|
|
||||||
| FGC | 老年代垃圾回收次数 |
|
|
||||||
| FGCT | 老年代垃圾回收总耗时 |
|
|
||||||
| GCT | 垃圾回收消耗总时间 |
|
|
||||||
|
|
||||||
##### 2. class 参数返回结果
|
|
||||||
|
|
||||||
-class 参数; 监视类装载、卸载数量、总空间以及装载所耗费的时间。
|
|
||||||
|
|
||||||
| 参数 | 解析 |
|
|
||||||
| -------- | --------------- |
|
|
||||||
| Loaded | 加载class的数量 |
|
|
||||||
| Bytes | 占用空间大小 |
|
|
||||||
| Unloaded | 未加载数量 |
|
|
||||||
| Bytes | 未加载占用空间 |
|
|
||||||
| Time | 时间 |
|
|
||||||
|
|
||||||
##### 3. gcmetacapacity 参数返回结果
|
|
||||||
|
|
||||||
元数据空间统计(-gcmetacapacity)
|
|
||||||
|
|
||||||
| 参数 | 描述 |
|
|
||||||
| ----- | ---------------------- |
|
|
||||||
| MCMN | 最小元数据容量 |
|
|
||||||
| MCMX | 最大元数据容量 |
|
|
||||||
| MC | 当前元数据空间大小 |
|
|
||||||
| CCSMN | 最小压缩类空间大小 |
|
|
||||||
| CCSMX | 最大压缩类空间大小 |
|
|
||||||
| CCSC | 当前压缩类空间大小 |
|
|
||||||
| YGC | 年轻代垃圾回收次数 |
|
|
||||||
| FGC | 老年代垃圾回收次数 |
|
|
||||||
| FGCT | 老年代垃圾回收消耗时间 |
|
|
||||||
| GCT | 垃圾回收消耗总时间 |
|
|
||||||
|
|
||||||
#### 4.2.3 jinfo:Java配置信息工具
|
|
||||||
|
|
||||||
命令格式:jinfo [option] ipd
|
|
||||||
|
|
||||||
在控制台输入 jinfo ,则会提示相关命令参数,可借助提示执行相关命令。
|
|
||||||
|
|
||||||
```shell
|
|
||||||
-flag <name> to print the value of the named VM flag
|
|
||||||
-flag [+|-]<name> to enable or disable the named VM flag
|
|
||||||
-flag <name>=<value> to set the named VM flag to the given value
|
|
||||||
-flags to print VM flags
|
|
||||||
-sysprops to print Java system properties
|
|
||||||
<no option> to print both of the above
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4.2.4 jmap:Java内存映像工具
|
|
||||||
|
|
||||||
`jmap`(JVM Memory Map for java)命令用于生成`堆转储快照`; 当然还可以使用`-XX:HeapDumpOnOutOfMemoryError` 参数,可以让虚拟机在OOM异常之后自动生产dump文件。
|
|
||||||
|
|
||||||
| 选项 | 作用 |
|
|
||||||
| ------------- | ------------------------------------------------------------ |
|
|
||||||
| -dump | 生成Java堆转储快照。 格式 -dump:[live,]format=b,file=< filename >,其中live子参数说明是否只dump出存活的对象 |
|
|
||||||
| finalizerinfo | 显示F-Queue中等待Finalizer线程执行finalize方法的对象 |
|
|
||||||
| -heap | 显示java堆详细信息,如使用哪种收集器、参数配置、分代状况等 |
|
|
||||||
| -histo | 显示堆中对象统计信息,包括类,实例数量、合计容量 |
|
|
||||||
| -F | 当虚拟机进程对 -dump选项没有响应时,可使用这个选项强制生成dump快照 |
|
|
||||||
|
|
||||||
#### 4.2.5 jhat:虚拟机堆转储快照分析工具
|
|
||||||
|
|
||||||
可用 VisualVM 或者其他可视化分析工具代替
|
|
||||||
|
|
||||||
#### 4.2.6 jstack:Java堆栈跟踪工具
|
|
||||||
|
|
||||||
jstack [ option ] vmid
|
|
||||||
|
|
||||||
| 参数 | 作用 |
|
|
||||||
| ---- | -------------------------------------------- |
|
|
||||||
| -F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
|
|
||||||
| -l | 除堆栈外,显示关于锁的附加信息 |
|
|
||||||
| -m | 如果调用本地方法的话,可以显示 c/C++的堆栈 |
|
|
||||||
|
|
||||||
### 4.3 JDK的可视化工具
|
|
||||||
|
|
||||||
官方工具1: JConsole(Java监视与管理控制台)
|
|
||||||
|
|
||||||
官方工具2: VisualVM(多合一故障处理工具)
|
|
||||||
|
|
||||||
IDEA下推荐插件:JProfiler
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 第十二章 Java内存模型
|
|
||||||
|
|
||||||
<div align="center"> <img src="https://github.com/heibaiying/LearningNotes/blob/master/pictures/java内存模型.png"/> </div></br>
|
|
||||||
|
|
||||||
关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、 如何从工作内存同步回主内存之类的实现细节,Java内存模型中定义了以下8种操作来完成 :
|
|
||||||
|
|
||||||
1. **lock(锁定)**:作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
|
|
||||||
2. **unlock(解锁)**:作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
|
|
||||||
3. **read(读取)**:作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
|
|
||||||
4. **load(载入)**:作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
|
|
||||||
5. **use(使用)**:作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
|
|
||||||
6. **assign(赋值)**:作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
|
|
||||||
7. **store(存储)**:作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
|
|
||||||
8. **write(写入)**:作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Java内存模型还规定了在执行上述8种基本操作时必须满足如下规则:**
|
|
||||||
|
|
||||||
1. 不允许read和load、 store和write操作之一单独出现,即不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起回写了但主内存不接受的情况出现。
|
|
||||||
2. 不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存。
|
|
||||||
3. 不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回主内存中。
|
|
||||||
4. 一个新的变量只能在主内存中“诞生”,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量,换句话说,就是对一个变量实施use、 store操作之前,必须先执行过了assign和load操作。
|
|
||||||
5. 一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。
|
|
||||||
6. 如果对一个变量执行lock操作,那将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
|
|
||||||
7. 如果一个变量事先没有被lock操作锁定,那就不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定住的变量。
|
|
||||||
8. 对一个变量执行unlock操作之前,必须先把此变量同步回主内存中(执行store、 write操作)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**先行发生原则:**
|
|
||||||
|
|
||||||
1. **程序次序规则**(Program Order Rule):在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。 准确地说,应该是控制流顺序而不是程序代码顺序,因为要考虑分支、 循环等结构。
|
|
||||||
2. **管程锁定规则**(Monitor Lock Rule):一个unlock操作先行发生于后面对同一个锁的lock操作。 这里必须强调的是同一个锁,而“后面”是指时间上的先后顺序。
|
|
||||||
3. **volatile变量规则**(Volatile Variable Rule):对一个volatile变量的写操作先行发生于后面对这个变量的读操作,这里的“后面”同样是指时间上的先后顺序。
|
|
||||||
4. **线程启动规则**(Thread Start Rule):Thread对象的start()方法先行发生于此线程的每一个动作。
|
|
||||||
5. **线程终止规则**(Thread Termination Rule):线程中的所有操作都先行发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、 Thread.isAlive()的返回值等手段检测到线程已经终止执行。
|
|
||||||
6. **线程中断规则**(Thread Interruption Rule):对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupted()方法检测到是否有中断发生。
|
|
||||||
7. **对象终结规则**(Finalizer Rule):一个对象的初始化完成(构造函数执行结束)先行发生于它的finalize()方法的开始。
|
|
||||||
8. **传递性**(Transitivity):如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C的结论。
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user