裸泳的猪

沾沾自喜其实最可悲

0%

线程创建方式

  1. 继承Thread类
    • start()方法是一个 native 方法,它将启动一个新线程,并执行 run()方法。
  2. 实现runnable接口,
    • 当一个类已经有继承了,此时可通过实现runnable接口来创建线程
  3. 采用线程池,实现callable接口(有返回),ExecutorService
    • 有返回值的任务必须实现 Callable 接口。执行Callable 任务后,可以获取一个Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务返回的 Object 了,再结合线程池接口 ExecutorService 就可以实现传说中有返回结果的多线程了。

多线程中的主要问题

  1. 可见性问题
    volatile修饰,保证了多线程之间的内存可见性
  2. 原子性问题
    AtomicInteger(Java中有那么一些类,是以Atomic开头的。这一系列的类我们称之为原子操作类。以最简单的类AtomicInteger为例。它相当于一个int变量,我们执行Int的 i++ 的时候并不是一个原子操作。而使用AtomicInteger的incrementAndGet却能保证原子操作)
  3. 有序性问题
    volatile 防止指令重排序
  4. 死锁的问题

synchronized 关键字

用法:

  1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;

  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

  3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个==类的所有对象==;

  4. 修改一个,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

阅读全文 »

1.Lambda 表达式

Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。

1.1 语法

lambda 表达式的语法格式如下:

(parameters) -> expression或(parameters) ->{statements; }

2.Java 8 方法引用

方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用一对冒号 :: 。

1
2
3
4
5
6
7
List names = new ArrayList();
names.add("Google");
names.add("Runoob");
names.add("Taobao");
names.add("Baidu");
names.add("Sina");
names.forEach(System.out::println);

3.默认方法

默认方法就是一个在接口里面有了一个实现的方法。

1
2
3
4
5
public interface vehicle {
default void print() {
System.out.println("我是一辆车!");
}
}

4.新工具

新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。

5.Stream API

5.1概念理解

新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

5.2生成流

在Java 8中,集合接口有两个方法来生成流:

stream() −为集合创建串行流。

parallelStream() − 为集合创建并行流。

1
public` `static` `void` `main(String[] args) {``  ``List<String> strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``, ``""``, ``"jkl"``);``  ``List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());``}

  

5.3 forEach

Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据。以下代码片段使用forEach 输出了10个随机数:

1
Random random = ``new` `Random();``random.ints().limit(``10``).forEach(System.out::println);

  

5.4 map

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

1
List<Integer> numbers = Arrays.asList(``3``, ``2``, ``2``, ``3``, ``7``, ``3``, ``5``);``// 获取对应的平方数``List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());

  

5.5 filter

filter 方法用于通过设置条件过滤出元素。以下代码片段使用filter 方法过滤出空字符串:

1
List<String>strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``,``""``, ``"jkl"``);``// 获取空字符串的数量``int` `count = (``int``) strings.stream().filter(string -> string.isEmpty()).count();

  

5.6 limit

limit 方法用于获取指定数量的流。以下代码片段使用 limit 方法打印出 10 条数据:

1
Random random = ``new` `Random();``random.ints().limit(``10``).forEach(System.out::println);

  

5.7 sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:

1
Random random = ``new` `Random();``random.ints().limit(``10``).sorted().forEach(System.out::println);

  

5.8 并行(parallel)程序

parallelStream 是流并行处理程序的代替方法。以下实例我们使用parallelStream 来输出空字符串的数量:

1
List<String> strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``, ``""``, ``"jkl"``);``// 获取空字符串的数量``int` `count = (``int``) strings.parallelStream().filter(string -> string.isEmpty()).count();

  

我们可以很容易的在顺序运行和并行直接切换。

5.9 Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors可用于返回列表或字符串:

1
List<String> strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``, ``""``, ``"jkl"``);``List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());``System.out.println(``"筛选列表: "` `+ filtered);``String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(``", "``));``System.out.println(``"合并字符串: "` `+ mergedString);

  

5.10 统计

另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。

1
List<Integer> numbers = Arrays.asList(``3``, ``2``, ``2``, ``3``, ``7``, ``3``, ``5``);``IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();``System.out.println(``"列表中最大的数 : "` `+ stats.getMax());``System.out.println(``"列表中最小的数 : "` `+ stats.getMin());``System.out.println(``"所有数之和 : "` `+ stats.getSum());``System.out.println(``"平均数 : "` `+ stats.getAverage());

6.Date Time API

加强对日期与时间的处理。

7.Optional 类

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常。

1
2
3
4
5
6
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);

8.Nashorn JavaScript 引擎

Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

参考:java8新特性详解及示例代码

Zookeeper基础概念

ZooKeeper是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。

客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的zookeeper机器来处理。对于写请求,这些请求会同时发给其他zookeeper机器并且达成一致后,请求才会返回成功。因此,随着zookeeper的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。

有序性是zookeeper中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个zookeeper最新的zxid。

ZooKeeper提供了什么?

区别于Eureka专用于注册中心的功能,zookeeper主要提供的能力是

  • 文件系统
  • 通知机制

Zookeeper文件系统

  • Zookeeper提供一个多层级的节点命名空间(节点称为znode)。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。
  • Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,每个节点的存放数据上限为1M

ZAB协议?

ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议。

ZAB协议包括两种基本的模式:崩溃恢复和消息广播

当整个zookeeper集群刚刚启动或者Leader服务器宕机、重启或者网络故障导致不存在过半的服务器与Leader服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的Leader服务器,然后集群中Follower服务器开始与新的Leader服务器进行数据同步,当集群中超过半数机器与该Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。

四种类型的数据节点 Znode

  • PERSISTENT-持久节点
    除非手动删除,否则节点一直存在于Zookeeper上
  • EPHEMERAL-临时节点
    临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。
  • PERSISTENT_SEQUENTIAL-持久顺序节点
    基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
  • EPHEMERAL_SEQUENTIAL-临时顺序节点
    基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。

Zookeeper Watcher 机制 – 数据变更通知

Zookeeper允许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据Watcher通知状态和事件类型做出业务上的改变。

工作机制:

  • 客户端注册watcher
  • 服务端处理watcher
  • 客户端回调watcher

Watcher特性总结:

  1. 一次性
    无论是服务端还是客户端,一旦一个Watcher被触发,Zookeeper都会将其从相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。
  2. 客户端串行执行
    客户端Watcher回调的过程是一个串行同步的过程。
  3. 轻量
    • Watcher通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。
    • 客户端向服务端注册Watcher的时候,并不会把客户端真实的Watcher对象实体传递到服务端,仅仅是在客户端请求中使用boolean类型属性进行了标记。
  4. watcher event异步发送watcher的通知事件从server发送到client是异步的,这就存在一个问题,不同的客户端和服务器之间通过socket进行通信,由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于Zookeeper本身提供了ordering guarantee,即客户端监听事件后,才会感知它所监视znode发生了变化。所以我们使用Zookeeper不能期望能够监控到节点每次的变化。Zookeeper只能保证最终的一致性,而无法保证强一致性。
  5. 注册watcher getData、exists、getChildren
  6. 触发watcher create、delete、setData
  7. 当一个客户端连接到一个新的服务器上时,watch将会被以任意会话事件触发。当与一个服务器失去连接的时候,是无法接收到watch的。而当client重新连接时,如果需要的话,所有先前注册过的watch,都会被重新注册。通常这是完全透明的。只有在一个特殊情况下,watch可能会丢失:对于一个未创建的znode的exist watch,如果在客户端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个watch事件可能会被丢失。

ZooKeeper实现分布式锁原理

其实如果有客户端C、客户端D等N个客户端争抢一个zk分布式锁,原理都是类似的。

  • 大家都是上来直接创建一个锁节点下的一个接一个的临时顺序节点
  • 如果自己不是第一个节点,就对自己上一个节点加监听器
  • 只要上一个节点释放锁,自己就排到前面去了,相当于是一个排队机制。

而且用临时顺序节点的另外一个用意就是,如果某个客户端创建临时顺序节点之后,不小心自己宕机了也没关系,zk感知到那个客户端宕机,会自动删除对应的临时顺序节点,相当于自动释放锁,或者是自动取消自己的排队。

主流消息队列选型

维度 Kafka RocketMQ RabbitMQ ActiveMQ
单机吞吐量 10万级 10万级 万级 万级
开发语言 Scala Java Erlang Java
高可用 分布式架构 分布式架构 主从架构 主从架构
性能 ms级 ms级 us级 ms级
功能 只支持主要的MQ功能 顺序消息、事务消息等功能完善 并发强、性能好、延时低 成熟的社区产品、文档丰富
  1. rocketmq主要为java开发,语言适配性好,
  2. 性能好,社区成熟。
  3. 支持顺序消息,事务消息。
  4. 支持分布式架构
阅读全文 »

消息队列

作用:

  1. 异步
  2. 削峰
  3. 解耦

异步

比如一个流程下需要正常的业务处理,中间需要发送短信,扣减优惠卷等,可以生产消息进入队列,由短信系统,优惠卷系统异步处理,减少主业务逻辑链路,提升效率。

解耦

异步,使用线程,线程池去做不是一样的么
线程,线程池代码需要固定,后续如果光是短信平台要改东西,主流程还要发布。消息队列可以实现解耦。

削峰

服务器,Redis,MySQL各自的承受能力都不一样,你直接全部流量照单全收肯定有问题啊,直接就打挂了。

阅读全文 »

1.spring是什么

Spring 是于 2003 年兴起的一个轻量级的 Java 开发框架,它是为了解决企业应用开发
的复杂性而创建的。Spring 的核心是控制反转(IoC)和面向切面编程(AOP)。


2.IOC控制反转

控制反转(IoC,Inversion of Control),是一个概念,是一种思想。指将传统上由程序代
码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对
象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,
依赖的管理。

spring对于IOC思想的具体实现就是:DI(依赖注入:DI(Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。)

DI具体用法和实现

ApplicationContext 接口(容器)

ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现
类有:ClassPathXmlApplicationContext(常用),FileSystemXmlApplicationContext。

  • 若 Spring 配置文件存放在项目的类路径下,则使用 ClassPathXmlApplicationContext 实现
    类进行加载。
  • ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。
    以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。
阅读全文 »

JVM的定义

JVM(Java Virtual Machine,Java虚拟机)。

JVM是JAVA实现跨平台的主要手段,事实上jvm是有较多的实现版本,各种系统下的JVM不同。

由于jvm是处在Java语言和操作系统之间的,所以它要向上提供对Java的支持,向下与操作系统良好交互。

jvm

JVM中的数据结构

主要分为基本类型引用类型

阅读全文 »

Eureka Server:注册中心服务端

注册中心服务端主要对外提供了三个功能:

  • 服务注册
    服务提供者启动时,会通过 Eureka Client 向 Eureka Server 注册信息,Eureka Server 会存储该服务的信息,Eureka Server 内部有二层缓存机制来维护整个注册表
  • 提供注册表
    服务消费者在调用服务时,如果 Eureka Client 没有缓存注册表的话,会从 Eureka Server 获取最新的注册表
    • 注册表的数据结构:registry的CocurrentHashMap,就是注册表的核心结构。同时维护注册表、拉取注册表、更新心跳时间,全部发生在内存里!这是Eureka Server非常核心的一个点。
  • 同步状态

高可用原理

其实每一个服务端(这里指实例)都内置了一个Eureka Client,也就是说一个服务端可以接受其他Client的注册,也可以作为一个Client注册到其他Server上,被其他Client发现和调用。一个服务端实例你可以理解为由一个Server+Client组成。

Eureka

Eureka Server 集群相互之间通过 Replicate 来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点

如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。

另外 Eureka Server 的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。所以,如果存在多个节点,只需要将节点之间两两连接起来形成通路,那么其它注册中心都可以共享信息。每个 Eureka Server 同时也是 Eureka Client,多个 Eureka Server 之间通过 P2P 的方式完成服务注册表的同步。

Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的。

Eureka 保证 AP,优先保证可用性,牺牲了一定的一致性。相对的zookeeper则是保证了CP,牺牲了部分的可用性。