目录

一、概述

1、简介

2、工作机制

3、特点

4、数据结构

5、应用场景

二、下载与安装

1、本地模式下载安装

2、配置参数(图见上图)

三、集群

1、集群安装

1)集群规划(多台虚拟机模拟)

2)解压安装

3)启动集群

2、选举机制(面试重点)

1)第一次启动

2)第二次启动

3、启动停止脚本

4、客户端命令行操作

1)命令行语法

2)参数信息

5、监听器

6、客户端API操作

1)IDEA环境搭建

2)创建客户端并连接zookeeper

3)创建子节点(必须先执行上一步初始化方法)

4)监听节点变化( 3)有设置监听器)

5)判断节点是否存在

7、客户端向服务端写数据流程

四、服务器动态上下线监听案例

1、需求分析

2、具体实现

1)创建节点

2)客户端连接集群,创建对应路径并写上名称

3)客户端集群上监听操作

五、分布式锁

1、案例分析

​2、分布式锁实现

3、测试

4、Curator框架实现分布式锁

1)原生JavaAPI开发存在问题

2)Curator实操

六、面试真题

1、选举 机制

1)第一次启动选举规则

2)第二次启动选举规则

2、生产 集群 安装多少 zk合适

3、常用命令


一、概述

1、简介

Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。

2、工作机制

是基于观察者模式设计的分布式服务管理框架,负责储存和管理大家都关心的数据,然后接收观察者的注册,一旦数据状态变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。

Zookeeper = 文件系统 + 通知机制

3、特点

① Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。

② 集群只要有半数以上节点存活,Zookeeper集群就能正常服务。适合安装奇数台服务器。

③ 全局数据一致每个Server保存一份相同的数据副本。

④ 先进先出的请求顺序执行。

⑤ 数据更新原子性。

⑥ 实行性。同步时间快。

4、数据结构

zookeeper数据模型结构与Unix文件系统很相似,树形结构,每个节点为ZNode,每个ZNode默认存储1MB数据。

5、应用场景

1)统一命名管理:对应用/服务进行统一命名,便于识别。

2)统一配置管理:所有节点的配置信息是一致的。配置文件修改后,能快速同步到各个节点上。

3)统一集群管理:实时监控节点变化。

4)服务器动态上下线:客户端能实时洞察到服务器上下线的变化。

5)软负载均衡:Zookeeper中会记录每台服务器的访问数,让访问数最少的服务器去处理最新的客户端需求。

二、下载与安装

1、本地模式下载安装

下载地址:Apache ZooKeeper  -> Download

必须在linux中安装java jdk

[root@ppitm-c ~]# java -version
openjdk version "1.8.0_275"
OpenJDK Runtime Environment (build 1.8.0_275-b01)
OpenJDK 64-Bit Server VM (build 25.275-b01, mixed mode)
[root@ppitm-c ~]#

下zookeeper压缩包到系统

[root@ppitm-c ~]# cd /opt
[root@ppitm-c opt]# ll
总用量 534788
-rw-r--r--.  1 root root   9311744 2月   2 23:06 apache-zookeeper-3.5.7-bin.tar.gz

解压:

tar -zxvf apache-zookeeper-3.5.7-bin.tar.gz -C /opt/

服务端启动脚本:zkServer.sh

客户端启动脚本:zkCli.sh

[root@ppitm-c bin]# pwd
/opt/apache-zookeeper-3.6.3-bin/bin
[root@ppitm-c bin]# ll
总用量 64
-rwxr-xr-x. 1 1000 1000   232 4月   9 2021 README.txt
-rwxr-xr-x. 1 1000 1000  2066 4月   9 2021 zkCleanup.sh
-rwxr-xr-x. 1 1000 1000  1158 4月   9 2021 zkCli.cmd
-rwxr-xr-x. 1 1000 1000  1620 4月   9 2021 zkCli.sh
-rwxr-xr-x. 1 1000 1000  1843 4月   9 2021 zkEnv.cmd
-rwxr-xr-x. 1 1000 1000  3690 4月   9 2021 zkEnv.sh
-rwxr-xr-x. 1 1000 1000  1286 4月   9 2021 zkServer.cmd
-rwxr-xr-x. 1 1000 1000  4559 4月   9 2021 zkServer-initialize.sh
-rwxr-xr-x. 1 1000 1000 11332 4月   9 2021 zkServer.sh
-rwxr-xr-x. 1 1000 1000   988 4月   9 2021 zkSnapShotToolkit.cmd
-rwxr-xr-x. 1 1000 1000  1377 4月   9 2021 zkSnapShotToolkit.sh
-rwxr-xr-x. 1 1000 1000   996 4月   9 2021 zkTxnLogToolkit.cmd
-rwxr-xr-x. 1 1000 1000  1385 4月   9 2021 zkTxnLogToolkit.sh
[root@ppitm-c bin]#

修改配置:配置文件改为zoo.cfg
    修改:dataDir=/opt/apache-zookeeper-3.6.3-bin/zkData

系统提供的只是临时地址,必须自己新建一个目录地址:mkdir zkData


启动服务端:bin/zkServer.sh start
启动客户端:bin/zkCli.sh

2、配置参数(图见上图)

1)tickTime=2000:通信心跳时间,Zookeeper服务器与客户端心跳时间,单位毫秒。

2)initLimit=10:LF初始通信时限(10个心跳),初始连接能容忍的最多心跳数。

3)syncLimit=5:LF同步通信时限(5个心跳),Leader和Follower之间通信时间如果超过syncLimit * tickTime,Leader认为Follwer死掉,从服务器列表中删除Follwer。

4)dataDir:保存Zookeeper中的数据

5)clientPort:2181:客户端连接端口

三、集群

1、集群安装

1)集群规划(多台虚拟机模拟)

比如在hadoop102、hadoop103、hadoop104节点上部署zookeeper。

2)解压安装

解压压缩包(第二章下载的压缩包相同)到/opt目录

修改配置文件zoo.zrx,并修改储存地址

在 /opt/zookeeper-3.5.7/zkData目录下创建一个 myid的文件,并在文件添加相应编号。(比如102服务器就添加2,103服务器就添加3,每个服务器的身份标识都要标注)

zoo.cfg末尾增加配置:server.唯一标识=服务器地址:主从交换信息端口:选举通信端口
    (比如:server.2=192.168.16.122:2888:3888)(每个服务端都配置)

########################cluster######################
server.2=hadoop102:2888:3888
server.3=hadoop103:2888:3888
server.4=hadoop104:2888:3888

3)启动集群

启动超过半数以上服务器将开始选举机制

2、选举机制(面试重点)

1)第一次启动

2)第二次启动

3、启动停止脚本

集群启动停止脚本 bin/zkServer.sh stop    或 用脚本(zk.sh stop)

#!/bin/bash
case $1 in
"start"){for i in hadoop102 hadoop103 hadoop104doecho -------zookeeper $i 启动 -------ssh $1 "/opt/module/zookeeper-3.5.7/bin/zkServer.sh start"done
}
;;
"stop"){for i in hadoop102 hadoop103 hadoop104doecho -------zookeeper $i 停止 -------ssh $1 "/opt/module/zookeeper-3.5.7/bin/zkServer.sh stop"done
}
;;
"status"){for i in hadoop102 hadoop103 hadoop104doecho -------zookeeper $i 状态 -------ssh $1 "/opt/module/zookeeper-3.5.7/bin/zkServer.sh status"done
}
;;

4、客户端命令行操作

1)命令行语法

ls /    查看节点
create 节点名 "数据" 创建永久节点
create -s 节点名 "数据"  创建带序号永久节点(可重复相同数据)
create -e 节点名 "数据"  创建临时节点
get -s /sanguo 获取节点对应的值
set -s /sanguo  修改节点对应的值

2)参数信息

[zk: hadoop102 :2181(CONNECTED) 5] ls s /
[zookeeper]cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x0
cversion = 1
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 1

czxid 创建节点的事务 zxid
每次修改ZooKeeper状态都会 产生一个 ZooKeeper事务 ID。事务 ID是 ZooKeeper中所
有修改总的次序。每 次 修改都有唯一的 zxid,如果 zxid1小于 zxid2,那么 zxid1在 zxid2之
前发生。

ctime znode被创建的毫秒数(从 1970年开始)

mzxid znode最后更新的事务 zxid

mtime znode最后修改的毫秒数(从 1970年开始)

pZxid znode最后更新的子节点 zxid

cversion:znode 子节点变化号,znode 子节点修改次数

dataversion:znode 数据变化号

aclVersion:znode 访问控制列表的变化号

ephemeralOwner:如果是临时节点,这个是znode 拥有者的session id。如果不是
临时节点则是0。

dataLength:znode 的数据长度

numChildren:znode 子节点数量

5、监听器

监听器及节点删除
get -w 节点名 监控节点数据变化(注册一次生效一次)
ls -w 节点名 监控节点数变化(注册一次生效一次)
delete 节点名 删除节点
deleteall 节点名 删除节点及子节点
stat 节点名 查看节点状态(不看节点值)

注册一次监听一次

6、客户端API操作

1)IDEA环境搭建

导入依赖

<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.6.2</version></dependency>
</dependencies>

创建log4j.properties到根目录(resources)

log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern =%d %p [%c]-%m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c]-%m%n

2)创建客户端并连接zookeeper

public class zkClient {private String connectString="192.168.177.129:2181";//连接zookeeper地址private int sessionTimeout=100000;//超时时间(建议调长)private ZooKeeper zkClient;@Beforepublic void init() throws IOException {//启动客户端并设置监听器zkClient = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent watchedEvent) {List<String> children = null;//监听根目录,用上面初始化的监听器try {children = zkClient.getChildren("/", true);System.out.println("----------------------------------");for (String child : children) {System.out.println(child);}System.out.println("----------------------------------");} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}});}
}

3)创建子节点(必须先执行上一步初始化方法)

@Test
public void create() throws KeeperException, InterruptedException {//创建节点(节点路径、内容、权限控制、什么样的节点)String nodeCreated = zkClient.create("/zhijia", "qyh.avi".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}

4)监听节点变化( 3)有设置监听器)

@Test
public void getChildren() throws KeeperException, InterruptedException {//    List<String> children = zkClient.getChildren("/", true);//监听根目录,用上面初始化的监听器
//
//    for (String child : children) {
//    System.out.println(child);
//        }Thread.sleep(50000);
}

5)判断节点是否存在

@Test
public void exist() throws KeeperException, InterruptedException {//监听某个节点是否存在Stat stat = zkClient.exists("/zhijia", false);System.out.println(stat == null ? "not exit" : "exist");
}

7、客户端向服务端写数据流程

四、服务器动态上下线监听案例

1、需求分析

2、具体实现

1)创建节点

[zk: localhost:2181(CONNECTED) 10] create /servers "servers"
Created /servers

2)客户端连接集群,创建对应路径并写上名称

package com.zhijia.case1;import org.apache.zookeeper.*;import java.io.IOException;/**服务器动态上下线————服务器注册* @author zhijia* @create 2022-01-27 11:03*/
public class DistributeServer {private String connectString="192.168.177.129:2181";private int sessionTimeout=100000;private ZooKeeper zk;public static void main(String[] args) throws IOException, KeeperException, InterruptedException {DistributeServer server = new DistributeServer();//1、获取zk连接server.getConnect();//2、注册服务器到zk集群server.regist(args[0]);//3、启动业务逻辑(睡觉)server.business();}//启动业务逻辑(睡觉)private void business() throws InterruptedException {Thread.sleep(Long.MAX_VALUE);}//注册服务器到zk集群private void regist(String hostname) throws KeeperException, InterruptedException {//节点路径,主机名,权限,什么样的节点String create = zk.create("/servers/"+hostname, hostname.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);System.out.println(hostname+" is online ");}//获取zk连接private void getConnect() throws IOException {zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent watchedEvent) {}});}
}

3)客户端集群上监听操作

package com.zhijia.case1;import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/**服务器动态上下线————客户端监听* @author zhijia* @create 2022-01-27 11:21*/
public class DistributeClient {private String connectString="192.168.177.129:2181";private int sessionTimeout=100000;private ZooKeeper zk;public static void main(String[] args) throws IOException, KeeperException, InterruptedException {DistributeClient client = new DistributeClient();//1、获取zk连接client.getConnect();//2、监听/servers下面子节点的增加和删除client.getServerList();//3、业务逻辑client.business();}//业务逻辑private void business() throws InterruptedException {Thread.sleep(Long.MAX_VALUE);}//获取zk连接private void getConnect() throws IOException {zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent watchedEvent) {try {getServerList();} catch (KeeperException e) {} catch (InterruptedException e) {e.printStackTrace();}}});}//监听/servers下面子节点的增加和删除public void getServerList() throws KeeperException, InterruptedException {List<String> children = zk.getChildren("/servers", true);ArrayList<String> servers = new ArrayList<String>();for (String child : children) {byte[] data = zk.getData("/servers/" + child, false, null);servers.add(new String(data));}System.out.println(servers);}
}

五、分布式锁

1、案例分析

 2、分布式锁实现

package com.zhijia.case2;import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;/*** @author zhijia* @create 2022-01-27 15:09*/
public class DistributedLock {private final String connectString="192.168.177.129:2181";private final int sessionTimeout=100000;private CountDownLatch countDownLatch=new CountDownLatch(1);private CountDownLatch waitLatch=new CountDownLatch(1);private final ZooKeeper zk;private String waitPath;private String currentMode;public DistributedLock() throws IOException, InterruptedException, KeeperException {//获取连接zk = new ZooKeeper(connectString, sessionTimeout, new Watcher() {public void process(WatchedEvent watchedEvent) {//连接上,释放if(watchedEvent.getState()==Event.KeeperState.SyncConnected){//监听状态为连接countDownLatch.countDown();}//waitLatch,释放if(watchedEvent.getType()==Event.EventType.NodeDeleted&&watchedEvent.getPath().equals(waitPath)){waitLatch.countDown();}}});//等待zk正常连接后才往下走countDownLatch.await();//判断根节点/locks是否存在Stat stat = zk.exists("/locks", false);if(stat==null){//需要创建根节点zk.create("/locks","locks".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);}}//加锁public void zkLock(){//创建对应的临时带序号节点try {currentMode = zk.create("/locks/" + "seq-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);//判断创建的节点是否是最小序号节点,若是就获取节点,若不是就监听前一个节点List<String> children = zk.getChildren("/locks", false);//一个就取值,多个就判断最小if(children.size()==1){return;}else {//排序Collections.sort(children);//获取节点名称String thisNode = currentMode.substring("/locks/".length());int index=children.indexOf(thisNode);if(index==-1){System.out.println("数据异常");}else if(index==0){return;}else {//监听前一个节点waitPath="/locks/"+children.get(index-1);zk.getData(waitPath,true,null);//等待监听waitLatch.await();return;}}} catch (KeeperException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}//解锁public void unZkLock(){//删除节点try {zk.delete(currentMode,-1);} catch (InterruptedException e) {e.printStackTrace();} catch (KeeperException e) {e.printStackTrace();}}
}

3、测试

package com.zhijia.case2;import org.apache.zookeeper.KeeperException;import java.io.IOException;/*** @author zhijia* @create 2022-01-27 16:10*/
public class DistributeLockTest {public static void main(String[] args) throws InterruptedException, IOException, KeeperException {final DistributedLock lock1 = new DistributedLock();final DistributedLock lock2 = new DistributedLock();new Thread(new Runnable() {public void run() {try {lock1.zkLock();System.out.println("线程1 启动:获取到锁");Thread.sleep(10*1000);lock1.unZkLock();System.out.println("线程1 :释放锁");} catch (InterruptedException e) {e.printStackTrace();}}}).start();new Thread(new Runnable() {public void run() {try {lock2.zkLock();System.out.println("线程2 启动:获取到锁");Thread.sleep(10*1000);lock2.unZkLock();System.out.println("线程2 :释放锁");} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}

4、Curator框架实现分布式锁

1)原生JavaAPI开发存在问题

① 会话连接是异步的,需要自己去处理。比如使用 CountDownLatch
② Watch需要重复注册,不然就不能生效
③ 开发的复杂性还是比较高的
④ 不支持多节点删除和创建。需要自己去递归

2)Curator实操

官网:http://curator.apache.org/index.html

① 添加依赖

        <dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.3.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.3.0</version></dependency><dependency><groupId>org.apache.curator</groupId><artifactId>curator-client</artifactId><version>4.3.0</version></dependency>

② 代码实现

package com.zhijia.case3;import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;/**zookeeper获取客户端连接* @author zhijia* @create 2022-01-28 9:47*/
public class CuratorLockTest {public static void main(String[] args) {//创建分布式锁1final InterProcessMutex lock1 = new InterProcessMutex(getCuratorFramework(), "/locks");//创建分布式锁2final InterProcessMutex lock2 = new InterProcessMutex(getCuratorFramework(), "/locks");new Thread(new Runnable() {public void run() {//获取锁try {lock1.acquire();System.out.println("线程1:获取锁");lock1.acquire();System.out.println("线程1:再次获取锁");Thread.sleep(5000);lock1.release();System.out.println("线程1:释放锁");lock1.release();System.out.println("线程1:再次释放锁");} catch (Exception e) {e.printStackTrace();}}}).start();new Thread(new Runnable() {public void run() {//获取锁try {lock2.acquire();System.out.println("线程2:获取锁");lock2.acquire();System.out.println("线程2:再次获取锁");Thread.sleep(5000);lock2.release();System.out.println("线程2:释放锁");lock2.release();System.out.println("线程2:再次释放锁");} catch (Exception e) {e.printStackTrace();}}}).start();}public static CuratorFramework getCuratorFramework() {//重试(多少秒重试,重试次数)ExponentialBackoffRetry policy = new ExponentialBackoffRetry(3000, 3);//客户端(连接主机,超时时间,连接失败后间隔多少秒重试)CuratorFramework client = CuratorFrameworkFactory.builder().connectString("192.168.177.129:2181").connectionTimeoutMs(10000).retryPolicy(policy).build();//启动客户端client.start();System.out.println("zookeeper启动成功");return client;}
}

六、面试真题

1、选举 机制

半数 机制 ,超过半数的投票通过,即通过。

1)第一次启动选举规则

投票过半数时,
服务器 id大的胜出

2)第二次启动选举规则


EPOCH大的直接胜出

EPOCH相同,事务 id大的胜出
③事务
id相同,服务器 id大的胜出

2、生产 集群 安装多少 zk合适

安装奇数台
生产经验:
⚫ 10台 服务器: 3台 zk
⚫ 20台 服务器: 5台 zk
⚫ 100台 服务器: 11台 zk
⚫ 200台 服务器: 11台 zk
服务器台数多:好处,提高可靠性;坏处:提高通信延时

3、常用命令

ls、 get、 create、 delete

Zookeeper入门(尚硅谷)相关推荐

  1. 尚硅谷全套课件整理:Java、前端、大数据、安卓、面试题

    目录 Java 尚硅谷 IT 精英计划 JavaSE 内部学习笔记.pdf 尚硅谷 Java 基础实战之银行项目.pdf 尚硅谷 Java 技术之 JDBC.pdf 尚硅谷 Java 技术之 Java ...

  2. 尚硅谷大数据技术Zookeeper教程-笔记01【Zookeeper(入门、本地安装、集群操作)】

    视频地址:[尚硅谷]大数据技术之Zookeeper 3.5.7版本教程_哔哩哔哩_bilibili 尚硅谷大数据技术Zookeeper教程-笔记01[Zookeeper(入门.本地安装.集群操作)] ...

  3. 尚硅谷Redis6从入门到精通

    本博客为尚硅谷课程笔记,课程来源:[尚硅谷]Redis 6 入门到精通 超详细 教程_哔哩哔哩_bilibili 本博客参考内容: https://blog.csdn.net/weixin_47872 ...

  4. 【Vue学习笔记】尚硅谷Vue2.0+Vue3.0全套教程丨vue.js从入门到精通

    尚硅谷Vue2.0+Vue3.0全套教程丨vue.js从入门到精通 1.Vue核心部分 1.1 Vue简介 1.1.1 Vue是什么? Vue是一套用于构建用户界面的渐进式JavaScript框架. ...

  5. [Vue]学习笔记目录 【Vue2与Vue3完结】 (尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通)

    文章目录 前言 遇见的问题及其解决方案 之前笔记 Vue2 Vue3 前言 本笔记根据如下笔记和视频进行整理 老师的课件笔记,不含视频 https://www.aliyundrive.com/s/B8 ...

  6. 尚硅谷Java入门视频教程导读及第一章

    尚硅谷Java入门视频教程导读及第一章 JAVA基础学习导读-编程入门 0.1概述 0.2 计算机硬件介绍 中央处理器(CPU) 存储设备 内存 比特(bit)和字节(byte) 内存 输入和输出设备 ...

  7. JVM从入门到精通(尚硅谷宋红康)

    不动笔墨不读书,先把书读厚,再把书读薄是我学习方式. 所以等理解了再整理一次笔记,目前笔记和视频一一对应. 笔记连载中 <尚硅谷2020最新版宋红康JVM> 第1章:JVM与Java体系结 ...

  8. 尚硅谷大数据技术Spark教程-笔记09【SparkStreaming(概念、入门、DStream入门、案例实操、总结)】

    尚硅谷大数据技术-教程-学习路线-笔记汇总表[课程资料下载] 视频地址:尚硅谷大数据Spark教程从入门到精通_哔哩哔哩_bilibili 尚硅谷大数据技术Spark教程-笔记01[SparkCore ...

  9. 尚硅谷Java入门视频教程第二章——Java基本语法

    尚硅谷Java入门视频教程第二章 第一章复习 课后习题 Java语言概述 第2章:Java基本语法 2.1 关键字和保留字 2.2 标识符(Identifier) 2.3 变量 2.3.1 变量基本概 ...

  10. 尚硅谷Java入门视频教程第十七章——Java9Java10Java11新特性

    尚硅谷Java入门视频教程第十七章--Java9&Java10&Java11新特性 第17章:Java9&Java10&Java11新特性 17.1 Java 9 的新 ...

最新文章

  1. python初学到底怎么学?大神三天快速学习python的方法留下的笔记
  2. 鼠标样式(cursor)
  3. 连接没反应_显示器USB接口的作用是什么?为什么会没有反应?
  4. 【数字信号处理】傅里叶变换性质 ( 序列傅里叶变换共轭对称性质 | 推论 )
  5. 修改Linux root用户名 后提示network manager启动失败修复
  6. jax-ws实现WebService
  7. 使用Docker Compose 搭建lnmp
  8. 【Qt】QModbusClient类
  9. php-redis扩展模块安装记录
  10. LeetCode篇之栈:155(常数时间复杂度内找最小栈)
  11. 任务提醒功能怎么实现
  12. JetBrains DataGrip 2018.2.3中文破解版 含jar文件注册码激活教程(转)
  13. 【电脑维修系列】妈妈再也不用担心 我装不了电脑系统 全攻略
  14. 【零基础】计算机网络技术基础与就业前景
  15. 【Microsoft Azure 的1024种玩法】五十五.Azure speech service之通过JavaScript快速实现文本转换为语音
  16. [学习IMU](MEMS 三轴加速计、三轴陀螺仪、三轴磁力计)6轴IMU+磁力计,9轴传感器讲解
  17. 网站安全性之js注入
  18. WordPress页面教程【2021】
  19. 解决win10任务栏卡死无响应点不动
  20. 怎么通过网络快速赚钱,无非是这4种方式!

热门文章

  1. RHCS+Conga+iSCSI+CLVM+GFS实现Web服务的共享存储HA集群
  2. Springboot面向网络直播平台的推荐系统y9tf8计算机毕业设计-课程设计-期末作业-毕设程序代做
  3. 0710学习总结(友元函数,string函数,引用)
  4. vscode找不到头文件的解决办法
  5. html中a标签是不是块元素,a标签是不是块元素,a标签是块级元素吗
  6. UV镜 不镀膜、单层镀膜和多层镀膜 , “暗中”测试 数码相机UV镜效果对比
  7. toad for mysql 彻底卸载_toad for mysql 下载
  8. 递归入门(C语言实现)
  9. 计算机重装系统的作用,经常重装系统对电脑有影响吗?听听专家怎么说!
  10. xshell连接centos vi编辑器不能使用小键盘