Merge 0cd6e109c747ebea8f299f150ed9dda4a7e00269 into b70121d377cb6005eb65f12b098cd5decd905669
This commit is contained in:
commit
1fca114595
64
README.md
64
README.md
@ -22,63 +22,63 @@
|
||||
|
||||
## :pencil2: 算法
|
||||
|
||||
- [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/notes/剑指%20Offer%20题解%20-%20目录.md)
|
||||
- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/notes/Leetcode%20题解%20-%20目录.md)
|
||||
- [算法](https://github.com/CyC2018/CS-Notes/blob/master/notes/算法%20-%20目录.md)
|
||||
- [剑指 Offer 题解](./notes/剑指%20Offer%20题解%20-%20目录.md)
|
||||
- [Leetcode 题解](./notes/Leetcode%20题解%20-%20目录.md)
|
||||
- [算法](./notes/算法%20-%20目录.md)
|
||||
- [字节跳动内推](assets/内推.md)
|
||||
|
||||
## :computer: 操作系统
|
||||
|
||||
- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/notes/计算机操作系统%20-%20目录.md)
|
||||
- [Linux](https://github.com/CyC2018/CS-Notes/blob/master/notes/Linux.md)
|
||||
- [计算机操作系统](./notes/计算机操作系统%20-%20目录.md)
|
||||
- [Linux](./notes/Linux.md)
|
||||
|
||||
## :cloud: 网络
|
||||
|
||||
- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/notes/计算机网络%20-%20目录.md)
|
||||
- [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/notes/HTTP.md)
|
||||
- [Socket](https://github.com/CyC2018/CS-Notes/blob/master/notes/Socket.md)
|
||||
- [计算机网络](./notes/计算机网络%20-%20目录.md)
|
||||
- [HTTP](./notes/HTTP.md)
|
||||
- [Socket](./notes/Socket.md)
|
||||
|
||||
## :floppy_disk: 数据库
|
||||
|
||||
- [数据库系统原理](https://github.com/CyC2018/CS-Notes/blob/master/notes/数据库系统原理.md)
|
||||
- [SQL 语法](https://github.com/CyC2018/CS-Notes/blob/master/notes/SQL%20语法.md)
|
||||
- [SQL 练习](https://github.com/CyC2018/CS-Notes/blob/master/notes/SQL%20练习.md)
|
||||
- [MySQL](https://github.com/CyC2018/CS-Notes/blob/master/notes/MySQL.md)
|
||||
- [Redis](https://github.com/CyC2018/CS-Notes/blob/master/notes/Redis.md)
|
||||
- [数据库系统原理](./notes/数据库系统原理.md)
|
||||
- [SQL 语法](./notes/SQL%20语法.md)
|
||||
- [SQL 练习](./notes/SQL%20练习.md)
|
||||
- [MySQL](./notes/MySQL.md)
|
||||
- [Redis](./notes/Redis.md)
|
||||
|
||||
## :coffee: Java
|
||||
|
||||
- [Java 基础](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20基础.md)
|
||||
- [Java 容器](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20容器.md)
|
||||
- [Java 并发](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20并发.md)
|
||||
- [Java 虚拟机](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20虚拟机.md)
|
||||
- [Java I/O](https://github.com/CyC2018/CS-Notes/blob/master/notes/Java%20IO.md)
|
||||
- [Java 基础](./notes/Java%20基础.md)
|
||||
- [Java 容器](./notes/Java%20容器.md)
|
||||
- [Java 并发](./notes/Java%20并发.md)
|
||||
- [Java 虚拟机](./notes/Java%20虚拟机.md)
|
||||
- [Java I/O](./notes/Java%20IO.md)
|
||||
|
||||
## :bulb: 系统设计
|
||||
|
||||
- [系统设计基础](https://github.com/CyC2018/CS-Notes/blob/master/notes/系统设计基础.md)
|
||||
- [分布式](https://github.com/CyC2018/CS-Notes/blob/master/notes/分布式.md)
|
||||
- [集群](https://github.com/CyC2018/CS-Notes/blob/master/notes/集群.md)
|
||||
- [攻击技术](https://github.com/CyC2018/CS-Notes/blob/master/notes/攻击技术.md)
|
||||
- [缓存](https://github.com/CyC2018/CS-Notes/blob/master/notes/缓存.md)
|
||||
- [消息队列](https://github.com/CyC2018/CS-Notes/blob/master/notes/消息队列.md)
|
||||
- [系统设计基础](./notes/系统设计基础.md)
|
||||
- [分布式](./notes/分布式.md)
|
||||
- [集群](./notes/集群.md)
|
||||
- [攻击技术](./notes/攻击技术.md)
|
||||
- [缓存](./notes/缓存.md)
|
||||
- [消息队列](./notes/消息队列.md)
|
||||
|
||||
## :art: 面向对象
|
||||
|
||||
- [面向对象思想](https://github.com/CyC2018/CS-Notes/blob/master/notes/面向对象思想.md)
|
||||
- [设计模式](https://github.com/CyC2018/CS-Notes/blob/master/notes/设计模式%20-%20目录.md)
|
||||
- [面向对象思想](./notes/面向对象思想.md)
|
||||
- [设计模式](./notes/设计模式%20-%20目录.md)
|
||||
|
||||
## :wrench: 工具
|
||||
|
||||
- [Git](https://github.com/CyC2018/CS-Notes/blob/master/notes/Git.md)
|
||||
- [Docker](https://github.com/CyC2018/CS-Notes/blob/master/notes/Docker.md)
|
||||
- [构建工具](https://github.com/CyC2018/CS-Notes/blob/master/notes/构建工具.md)
|
||||
- [正则表达式](https://github.com/CyC2018/CS-Notes/blob/master/notes/正则表达式.md)
|
||||
- [Git](./notes/Git.md)
|
||||
- [Docker](./notes/Docker.md)
|
||||
- [构建工具](./notes/构建工具.md)
|
||||
- [正则表达式](./notes/正则表达式.md)
|
||||
|
||||
## :watermelon: 编码实践
|
||||
|
||||
- [代码可读性](https://github.com/CyC2018/CS-Notes/blob/master/notes/代码可读性.md)
|
||||
- [代码风格规范](https://github.com/CyC2018/CS-Notes/blob/master/notes/代码风格规范.md)
|
||||
- [代码可读性](./notes/代码可读性.md)
|
||||
- [代码风格规范](./notes/代码风格规范.md)
|
||||
|
||||
## :memo: 后记
|
||||
|
||||
|
BIN
assets/1641890623956-ani--线程状态转换.jpg
Normal file
BIN
assets/1641890623956-ani--线程状态转换.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 76 KiB |
@ -28,6 +28,7 @@
|
||||
* [选择器](#选择器)
|
||||
* [套接字 NIO 实例](#套接字-nio-实例)
|
||||
* [内存映射文件](#内存映射文件)
|
||||
* [待补充AIO]
|
||||
* [对比](#对比)
|
||||
* [八、参考资料](#八参考资料)
|
||||
<!-- GFM-TOC -->
|
||||
|
@ -11,6 +11,7 @@
|
||||
* [Daemon](#daemon)
|
||||
* [sleep()](#sleep)
|
||||
* [yield()](#yield)
|
||||
* [线程通信方式](#线程通信方式)
|
||||
* [三、中断](#三中断)
|
||||
* [InterruptedException](#interruptedexception)
|
||||
* [interrupted()](#interrupted)
|
||||
@ -149,12 +150,12 @@ public static void main(String[] args) {
|
||||
|
||||
### Executor
|
||||
|
||||
Executor 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。
|
||||
Executors 管理多个异步任务的执行,而无需程序员显式地管理线程的生命周期。这里的异步是指多个任务的执行互不干扰,不需要进行同步操作。
|
||||
|
||||
主要有三种 Executor:
|
||||
|
||||
- CachedThreadPool:一个任务创建一个线程;
|
||||
- FixedThreadPool:所有任务只能使用固定大小的线程;
|
||||
- FixedThreadPool:所有任务只能使用固定大小的线程,但是线程池默认使用了无界队列;
|
||||
- SingleThreadExecutor:相当于大小为 1 的 FixedThreadPool。
|
||||
|
||||
```java
|
||||
@ -210,6 +211,42 @@ public void run() {
|
||||
}
|
||||
```
|
||||
|
||||
### 线程通信方式
|
||||
|
||||
(来自https://www.nowcoder.com/exam/interview/75826387/test?paperId=50270024)
|
||||
|
||||
在Java中,常用的线程通信方式有两种,分别是利用**Monitor实现**线程通信、利用**Condition实现**线程通信。
|
||||
|
||||
线程同步是线程通信的前提,所以究竟采用哪种方式实现通信,取决于线程同步的方式。 如果是采用**synchronized**关键字进行同步,则需要依赖**Monitor**(同步监视器)实现线程通信,Monitor就是锁对象。在synchronized同步模式下,锁对象可以是任意的类型,所以通信方法自然就被定义在Object类中了,这些方法包括:wt()、notify()、notifyAll()。一个线程通过Monitor调用wt()时,它就会释放锁并在此等待。当其他线程通过Monitor调用notify()时,则会唤醒在此等待的一个线程。当其他线程通过Monitor调用notifyAll()时,则会唤醒在此等待的所有线程。
|
||||
|
||||
JDK1.5新增了Lock接口及其实现类,提供了更为灵活的同步方式。如果是采用**Lock对象**进行同步,则需要依赖**Condition**实现线程通信,Condition对象是由Lock对象创建出来的,它依赖于Lock对象。Condition对象中定义的通信方法,与Object类中的通信方法类似,它包括awt()、signal()、signalAll()。通过名字就能看出它们的含义了,当通过Condition调用awt()时当前线程释放锁并等待,当通过Condition调用signal()时唤醒一个等待的线程,当通过Condition调用signalAll()时则唤醒所有等待的线程。
|
||||
|
||||
加分回答--线程同步是基于同步队列实现的,而线程通信是基于等待队列实现的。当调用等待方法时,即将当前线程加入等待队列。当调用通知方法时,即将等待队列中的一个或多个线程转移回同步队列。因为synchronized只有一个Monitor,所以它就只有一个等待队列。而Lock对象可以创建出多个Condition,所以它拥有多个等待队列。多个等待队列带来了极大的灵活性,所以基于Condition的通信方式更为推荐。 比如,在实现生产消费模型时,生产者要通知消费者、消费者要通知生产者。相反,不应该出现生产者通知生产者、消费者通知消费者这样的情况。如果使用synchronized实现这个模型,由于它只有一个等待队列,所以只能把生产者和消费者加入同一个队列,这就会导致生产者通知生产者、消费者通知消费者的情况出现。采用Lock实现这个模型时,由于它有多个等待队列,可以有效地将这两个角色区分开,就能避免出现这样的问题。
|
||||
|
||||
|
||||
|
||||
### **关于线程池**
|
||||
【线程池的意义】
|
||||
线程池可以有效地管理线程:它可以**管理线程的数量**,可以避免无节制的创建线程,导致超出系统负荷直至崩溃。它还可以**让线程复用**,可以大大地减少创建和销毁线程所带来的开销。
|
||||
【**线程池的核心参数**】
|
||||
线程池需要依赖一些参数来控制任务的执行流程,其中最重要的参数有:corePoolSize(核心线程数)、workQueue(等待队列)、maximunPoolSize(最大线程数)、handler(拒绝策略)、keepAliveTime(空闲线程存活时间)。
|
||||
【线程池的运作步骤】
|
||||
当我们向线程池提交一个任务之后,线程池按照如下步骤处理这个任务:
|
||||
|
||||
1. 判断线程数是否达到corePoolSize,若没有则新建线程执行该任务,否则进入下一步。
|
||||
2. 判断等待队列是否已满,若没有则将任务放入等待队列,否则进入下一步。
|
||||
3. 判断线程数是否达到maximunPoolSize,如果没有则新建线程执行任务,否则进入下一步。
|
||||
4. 采用初始化线程池时指定的拒绝策略,拒绝执行该任务。
|
||||
5. 新建的线程处理完当前任务后,不会立刻关闭,而是继续处理等待队列中的任务。如果线程的空闲时间达到了keepAliveTime,则线程池会销毁一部分线程,将线程数量收缩至corePoolSize。 第2步中的队列可以有界也可以无界。若指定了无界的队列,则线程池永远无法进入第3步,相当于废弃了maximunPoolSize参数。这种用法是十分危险的,如果任务在队列中产生大量的堆积,就很容易造成内存溢出。
|
||||
|
||||
【线程池池创建工具--建议用**ThreadPoolExecutor**】
|
||||
JDK为我们提供了一个名为Executors的线程池的创建工具,该工具创建出来的就是带有无界队列的线程池,所以一般在工作中我们是不建议使用这个类来创建线程池的。 第4步中的拒绝策略主要有4个:让调用者自己执行任务、直接抛出异常、丢弃任务不做任何处理、删除队列中最老的任务并把当前任务加入队列。这4个拒绝策略分别对应着RejectedExecutionHandler接口的4个实现类,我们也可以基于这个接口实现自己的拒绝策略。 在Java中,线程池的实际类型为ThreadPoolExecutor,它提供了线程池的常规用法。该类还有一个子类,名为ScheduledThreadPoolExecutor,它对定时任务提供了支持。在子类中,我们可以周期性地重复执行某个任务,也可以延迟若干时间再执行某个任务。
|
||||
在Java中正常创建线程池应该使用ThreadPoolExecutor类。虽然Executors类可以方便地创建线程池,但它使用的默认参数可能不适合所有情况。例如,Executors.newFixedThreadPool方法创建的线程池默认使用无界队列,可能会导致内存溢出。此外,Executors类隐藏了线程池的细节,使得无法对其进行更灵活的配置和优化。因此,建议使用ThreadPoolExecutor类手动创建线程池,并根据具体情况进行参数配置。
|
||||
|
||||
【线程池的生命周期状态】 线程池的生命周期包含5个状态:RUNNING、SHUTDOWN、STOP、TIDING、TERMINATED。这5种状态的状态值分别是:-1、0、1、2、3。在线程池的生命周期中,它的状态只能由小到大迁移,是不可逆的。 1. RUNNING:表示线程池正在运行。 2. SHUTDOWN:执行shutdown()时进入该状态,此时队列不会清空,线程池会等待任务执行完毕。 3. STOP:执行shutdownNow()时进入该状态,此时现线程池会清空队列,不再等待任务的执行。 4. TIDING:当线程池及队列为空时进入该状态,此时线程池会执行钩子函数,目前该函数是一个空的实现。 5. TERMINATED:钩子函数执行完毕后,线程进入该状态,表示线程池已经死亡。
|
||||
(来自https://www.nowcoder.com/exam/interview/75826387/test?paperId=50270024)
|
||||
|
||||
|
||||
## 三、中断
|
||||
|
||||
一个线程执行完毕之后会自动结束,如果在运行过程中发生异常也会提前结束。
|
||||
@ -334,6 +371,7 @@ future.cancel(true);
|
||||
|
||||
Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问,第一个是 JVM 实现的 synchronized,而另一个是 JDK 实现的 ReentrantLock。
|
||||
|
||||
|
||||
### synchronized
|
||||
|
||||
**1. 同步一个代码块**
|
||||
@ -489,6 +527,15 @@ public static void main(String[] args) {
|
||||
|
||||
|
||||
### 比较
|
||||
| **比较点** | **synchronized** | **ReentrantLock** |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---------------------------------------------- |
|
||||
| **锁的实现** | JVM实现 | JDK实现 |
|
||||
| **性能** | 新版本Java已优化很多,例如自旋锁等,性能与ReentrantLock大致相同 | 与ReentrantLock大致相同 |
|
||||
| **等待是否可中断**(当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情。) | 不可中断 | 可中断 |
|
||||
| **公平锁**(指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁) | 非公平 | 默认非公平,但也可以是公平的 |
|
||||
| **锁绑定多个条件** | | 一个ReentrantLock可以同时绑定多个Condition对象 |
|
||||
|
||||
|
||||
|
||||
**1. 锁的实现**
|
||||
|
||||
@ -726,9 +773,29 @@ after
|
||||
|
||||
[Java SE 9 Enum Thread.State](https://docs.oracle.com/javase/9/docs/api/java/lang/Thread.State.html)
|
||||
|
||||
## 七、J.U.C - AQS
|
||||

|
||||
|
||||
## 七、J.U.C - AQS(AbstractQueuedSynchornizer)
|
||||
**关于AQS**
|
||||
AbstractQueuedSynchronizer)是**队列同步器,是用来构建锁的基础框架**,Lock实现类都是基于AQS实现的。AQS是基于**模板方法模式进行设计的,所以锁的实现需要继承AQS并重写它指定的方法**。A**QS内部定义了一个FIFO的队列来实现线程的同步,同时还定义了同步状态来记录锁的信息**。 AQS的模板方法,将管理同步状态的逻辑提炼出来形成标准流程,这些方法主要包括:独占式获取同步状态、独占式释放同步状态、共享式获取同步状态、共享式释放同步状态。以独占式获取同步状态为例,它的大致流程是:
|
||||
|
||||
1. 尝试以独占方式获取同步状态。
|
||||
|
||||
2. 如果状态获取失败,则将当前线程加入同步队列。
|
||||
|
||||
3. 自旋处理同步状态,如果当前线程位于队头,则唤醒它并让它出队,否则使其进入阻塞状态。 其中,有些步骤无法在父类确定,则提炼成空方法留待子类实现。例如,第一步的尝试操作,对于公平锁和非公平锁来说就不一样,所以子类在实现时需要按照场景各自实现这个方法。 AQS的同步队列,是一个双向链表,AQS则持有链表的头尾节点。对于尾节点的设置,是存在多线程竞争的,所以采用CAS的方式进行修改。对于头节点设置,则一定是拿到了同步状态的线程才能处理,所以修改头节点不需要采用CAS的方式。 AQS的同步状态,是一个int类型的整数,它在表示状态的同时还能表示数量。通常情况下,状态为0时表示无锁,状态大于0时表示锁的重入次数。另外,在读写锁的场景中,这个状态标志既要记录读锁又要记录写锁。于是,锁的实现者就将状态表示拆成高低两部分,高位存读锁、低位存写锁。 加分回答 同步状态需要在并发环境下修改,所以需要保证其线程安全。由于AQS本身就是锁的实现工具,所以不适合用锁来保证其线程安全,因为如果你用一个锁来定义另一个锁的话,那干脆直接用synchronized算了。实际上,同步状态是被volatile修饰的,该关键字可以保证状态变量的内存可见性,从而解决了线程安全问题。(来自https://www.nowcoder.com/exam/interview/75826387/test?paperId=50270024)
|
||||
|
||||
java.util.concurrent(J.U.C)大大提高了并发性能,AQS 被认为是 J.U.C 的核心。
|
||||
1. **原子类** 从JDK 1.5开始,并发包下提供了atomic子包,这个包中的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式。在atomic包里一共提供了17个类,属于4种类型的原子更新方式,分别是原子更新基本类型、原子更新引用类型、原子更新属性、原子更新数组。
|
||||
|
||||
2. **锁** 从JDK 1.5开始,并发包中新增了Lock接口以及相关实现类用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了隐式获取释放锁的便捷性,但是却拥有了多种synchronized关键字所不具备的同步特性,包括:**可中断地获取锁**、**非阻塞地获取锁**、**可超时地获取锁**。
|
||||
|
||||
3. **线程池** 从JDK 1.5开始,并发包下新增了内置的线程池。其中,**ThreadPoolExecutor**类代表常规的线程池,而它的子类ScheduledThreadPoolExecutor对定时任务提供了支持,在子类中我们可以周期性地重复执行某个任务,也可以延迟若干时间再执行某个任务。此外,Executors是一个用于创建线程池的工具类,由于该类创建出来的是带有无界队列的线程池,所以在使用时要慎重。
|
||||
|
||||
4. **并发容器** 从JDK 1.5开始,并发包下新增了大量高效的并发的容器,这些容器按照实现机制可以分为三类。第一类是以**降低锁粒度来**提高并发性能的容器,它们的类名以Concurrent开头,如ConcurrentHashMap。第二类是采用**写时复制技术实**现的并发容器,它们的类名以CopyOnWrite开头,如CopyOnWriteArrayList。第三类是采用**Lock实现的阻塞队列,内部创建两个Condition分别用于生产者和消费者的等待**,这些类都实现了BlockingQueue接口,如ArrayBlockingQueue。
|
||||
|
||||
5. **同步工具** 从JDK 1.5开始,并发包下新增了几个有用的并发工具类,一样可以保证线程安全。其中,Semaphore类代表信号量,可以控制同时访问特定资源的线程数量;CountDownLatch类则允许一个或多个线程等待其他线程完成操作;CyclicBarrier可以让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会打开,所有被屏障拦截的线程才会继续运行。
|
||||
(来自https://www.nowcoder.com/exam/interview/75826387/test?paperId=50270024)
|
||||
|
||||
### CountDownLatch
|
||||
|
||||
@ -814,6 +881,13 @@ public class CyclicBarrierExample {
|
||||
before..before..before..before..before..before..before..before..before..before..after..after..after..after..after..after..after..after..after..after..
|
||||
```
|
||||
|
||||
### Exchanger
|
||||
Java中的Exchanger类是一个同步工具类,用于在两个线程之间交换数据。它提供了一个exchange()方法,当两个线程都调用该方法时,它们会被阻塞,直到彼此都调用了该方法,然后交换数据并返回。
|
||||
|
||||
Exchanger类的实现原理是基于AQS(AbstractQueuedSynchronizer)同步器。当一个线程调用exchange()方法时,它会尝试获取同步器的锁,如果同步器的状态为0,则表示没有其他线程在等待交换数据,该线程会将自己加入到同步器的等待队列中,并阻塞自己。当另一个线程也调用了exchange()方法时,它会尝试获取同步器的锁,如果同步器的状态为1,则表示有一个线程在等待交换数据,该线程会将自己从等待队列中取出,并与另一个线程交换数据,然后释放同步器的锁,使得两个线程都可以继续执行。
|
||||
|
||||
需要注意的是,Exchanger类只能用于两个线程之间交换数据,如果需要多个线程之间交换数据,可以使用CyclicBarrier或CountDownLatch等其他同步工具类。
|
||||
|
||||
### Semaphore
|
||||
|
||||
Semaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。
|
||||
|
80
notes/Java与C++后端开发.md
Normal file
80
notes/Java与C++后端开发.md
Normal file
@ -0,0 +1,80 @@
|
||||
# 关键字
|
||||
|
||||
| 关键字 | Java | C++ |
|
||||
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| **volatile** | 它表示**可见性**。即被该关键字修改的变量的读操作一定在该变量的写更新后。 | (1)**易变性**--在汇编层面来看,即读取该变量的值时直接从内存中读取,而不是从寄存器。<br />(2)"**不可优化**"特性。<br />(3)"**顺序性**"--保证volatile变量间的顺序性,编译器不会进行乱序优化。 |
|
||||
| **static** | (1)修饰类中成员变量。<br />(2)修饰类中方法。表示该方法属于整个类而不属于类的特定实例<br />(3)修饰代码块。 | 控制变更的**存储方式和可见性**<br />(1)修饰局部变量——原本局部变量是存放在栈区的,并且局部变量的生命周期在该语句块执行结束时便结束了。但是如果**用static进行修饰的话,该变量便存放在静态数据区,其生命周期一直持续到整个程序执行结束**。但是在这里要注意的是,虽然用static对局部变量进行修饰过后,其生命周期以及存储空间发生了变化,但是其作用域并没有改变,其仍然是一个局部变量,作用域仅限于该语句块。<br />(2)修饰全局变量——原本对于一个全局变量,它既可以在本源文件中被访问到,也可以在同一个工程的其它源文件中被访问(只需用extern进行声明即可)。用static对全局变量进行修饰**改变了其作用域的范围,由原来的整个工程可见变为本源文件可见**。<br />(3)修饰函数。——与修饰全局变量大同小异,就是改变了函数的作用域。<br />(4)C++中的static(中的某个函数用static进行修饰,则表示该函数属于一个类而不是属于此类的任何特定对象;如果对类中的某个变量进行static修饰,表示该变量为类以及其所有的对象所有。它们在存储空间中都只存在一个副本。可以通过类和对象去调用。 ) |
|
||||
| **const**(常量限定符) | (1)修饰**类**。——表明该类不能被继承<br />(2)修饰对象。——表明该对象引用不可修改,当然对象的值依然可被修改<br />(3) | const名叫常量限定符,用来限定特定变量,以通知编译器该变量是不可修改的。习惯性的使用const,可以避免在函数中对某些不应修改的变量造成可能的改动。<br/> <br/>(1)const修饰基本数据类型<br/><br/> 1.const修饰一般常量及数组<br/> <br/> 基本数据类型,修饰符const可以用在类型说明符前,也可以用在类型说明符后,其结果是一样的。在使用这些常量的时候,只要不改变这些常量的值便好。 <br/> <br/> 2.const修饰指针变量*及引用变量& <br/> <br/>如果const位于星号*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;<br/><br/>如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。<br/><br/>(2)const应用到函数中, <br/><br/> 1.作为参数的const修饰符<br/> <br/> 调用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,保护了原对象的属性。<br/> [注意]:参数const通常用于参数为指针或引用的情况; <br/> <br/> 2.作为函数返回值的const修饰符<br/> <br/> 声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。<br/><br/>(3)const在类中的用法<br/><br/>不能在类声明中初始化const数据成员。正确的使用const实现方法为:const数据成员的初始化只能在类构造函数的初始化表中进行<br/>类中的成员函数:A fun4()const; 其意义上是不能修改所在类的的任何变量。<br/><br/>(4)const修饰类对象,定义常量对象 <br/>常量对象只能调用常量函数,别的成员函数都不能调用。<br/><br/>http://www.cnblogs.com/wintergrass/archive/2011/04/15/2015020.html |
|
||||
| **extern** | —— | 在C语言中,修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。<br/><br/>注意extern声明的位置对其作用域也有关系,如果是在main函数中进行声明的,则只能在main函数中调用,在其它函数中不能调用。其实要调用其它文件中的函数和变量,只需把该文件用#include包含进来即可,为啥要用extern?因为用extern会加速程序的编译过程,这样能节省时间。<br/><br/>在C++中extern还有另外一种作用,用于指示C或者C++函数的调用规范。比如在C++中调用C库函数,就需要在C++程序中用extern “C”声明要引用的函数。这是给链接器用的,告诉链接器在链接的时候用C函数规范来链接。主要原因是C++和C程序编译完成后在目标代码中命名规则不同,用此来解决名字匹配的问题。 |
|
||||
|
||||
#### C/C++特有---宏定义和展开、内联函数区别
|
||||
|
||||
**内联函数是代码被插入到调用者代码处的函数**。如同 #define 宏,内联函数通过避免被调用的开销来**提高执行效率**,尤其是它能够通过调用(“过程化集成”)被编译器优化。 **宏定义不检查函数参数,返回值什么的,只是展开,相对来说,内联函数会检查参数类型,所以更安全。** 内联函数和宏很类似,而区别在于,**宏是由预处理器对宏**进行替代,而**内联函数是通过编译器控制**来实现的。而且内联函数是真正的函数,只是在需要用到的时候,内联函数像宏一样的展开,所以取消了函数的参数压栈,减少了调用的开销。
|
||||
|
||||
宏是预编译器的输入,然后宏展开之后的结果会送去编译器做语法分析。宏与函数等处于不同的级别,操作不同的实体。宏操作的是 token, 可以进行 token的替换和连接等操作,在语法分析之前起作用。而函数是语言中的概念,会在语法树中创建对应的实体,内联只是函数的一个属性。
|
||||
对于问题:有了函数要它们何用?答案是:一:函数并不能完全替代宏,有些宏可以在当前作用域生成一些变量,函数做不到。二:内联函数只是函数的一种,内联是给编译器的提示,告诉它最好把这个函数在被调用处展开,省掉一个函数调用的开销(压栈,跳转,返回)
|
||||
|
||||
内联函数也有一定的局限性。就是函数中的执行代码不能太多了,如果,内联函数的函数体过大,一般的编译器会放弃内联方式,而采用普通的方式调用函数。这样,内联函数就和普通函数执行效率一样
|
||||
|
||||
内联函数必须是和函数体申明在一起,才有效。
|
||||
|
||||
[宏定义和内联函数区别](http://www.cnblogs.com/chengxuyuancc/archive/2013/04/04/2999844.html)
|
||||
|
||||
# STL原理及实现
|
||||
|
||||
> Java中集合类(接口collection的子类)、map接口
|
||||
|
||||
STL提供六大组件,彼此可以组合套用:
|
||||
|
||||
> 1、容器(Containers):各种数据结构,如:序列式容器vector、list、deque、关联式容器set、map、multiset、multimap。用来存放数据。从实现的角度来看,STL容器是一种class template。
|
||||
|
||||
> 2、算法(algorithms):各种常用算法,如:sort、search、copy、erase。从实现的角度来看,STL算法是一种 function template。注意一个问题**:任何的一个STL算法,都需要获得由一对迭代器所标示的区间,用来表示操作范围**。这一对迭代器所标示的区间都是前闭后开区间,例如[first, last)
|
||||
|
||||
> 3、迭代器(iterators):容器与算法之间的胶合剂,**是所谓的“泛型指针”**。共有五种类型,以及其他衍生变化。从实现的角度来看,迭代器是一种将 operator*、operator->、operator++、operator- - 等指针相关操作进行重载的class template。所有STL容器都有自己专属的迭代器,只有容器本身才知道如何遍历自己的元素。原生指针(native pointer)也是一种迭代器。
|
||||
|
||||
> 4、仿函数(functors):行为类似函数,可作为算法的某种策略(policy)。从实现的角度来看,仿函数是一种重载了operator()的class或class template。一般的函数指针也可视为狭义的仿函数。
|
||||
|
||||
> 5、配接器(adapters):一种用来修饰容器、仿函数、迭代器接口的东西。例如:STL提供的queue 和 stack,虽然看似容器,但其实只能算是一种容器配接器,因为它们的底部完全借助deque,所有操作都由底层的deque供应。改变 functors接口者,称为function adapter;改变 container 接口者,称为container adapter;改变iterator接口者,称为iterator adapter。
|
||||
|
||||
> 6、配置器(allocators):负责空间配置与管理。从实现的角度来看,**配置器是一个实现了动态空间配置、空间管理、空间释放的class template**。
|
||||
|
||||
这六大组件的交互关系:container(容器) 通过 allocator(配置器) 取得数据储存空间,algorithm(算法)通过 iterator(迭代器)存取 container(容器) 内容,functor(仿函数) 可以协助 algorithm(算法) 完成不同的策略变化,adapter(配接器) 可以修饰或套接 functor(仿函数)
|
||||
|
||||
序列式容器:
|
||||
vector-数组,元素不够时再重新分配内存,拷贝原来数组的元素到新分配的数组中。
|
||||
list-单链表。
|
||||
deque-分配中央控制器map(并非map容器),map记录着一系列的固定长度的数组的地址.记住这个map仅仅保存的是数组的地址,真正的数据在数组中存放着.deque先从map中央的位置(因为双向队列,前后都可以插入元素)找到一个数组地址,向该数组中放入数据,数组不够时继续在map中找空闲的数组来存数据。当map也不够时重新分配内存当作新的map,把原来map中的内容copy的新map中。所以使用deque的复杂度要大于vector,尽量使用vector。
|
||||
|
||||
stack-基于deque。
|
||||
queue-基于deque。
|
||||
heap-完全二叉树,使用最大堆排序,以数组(vector)的形式存放。
|
||||
priority_queue-基于heap。
|
||||
slist-双向链表。
|
||||
|
||||
关联式容器:
|
||||
set,map,multiset,multimap-基于红黑树(RB-tree),一种加上了额外平衡条件的二叉搜索树。
|
||||
|
||||
hash table-散列表。将待存数据的key经过映射函数变成一个数组(一般是vector)的索引,例如:数据的key%数组的大小=数组的索引(一般文本通过算法也可以转换为数字),然后将数据当作此索引的数组元素。有些数据的key经过算法的转换可能是同一个数组的索引值**(碰撞问题,可以用线性探测,二次探测来解决**),STL是用开链的方法来解决的,每一个数组的元素维护一个list,他把相同索引值的数据存入一个list,这样当list比较短时执行删除,插入,搜索等算法比较快。
|
||||
|
||||
hash_map,hash_set,hash_multiset,hash_multimap-基于hashtable。
|
||||
|
||||
[STL六大组件] (http://blog.csdn.net/chenguolinblog/article/details/30336805)
|
||||
什么是“标准非STL容器”?
|
||||
|
||||
list和vector有什么区别?
|
||||
|
||||
> vector拥有一段连续的内存空间,因此支持随机存取,如果需要高效的随即存取,而不在乎插入和删除的效率,使用vector。
|
||||
> list拥有一段不连续的内存空间,因此不支持随机存取,如果需要大量的插入和删除,而不关心随即存取,则应使用list。
|
||||
|
||||
# 虚函数
|
||||
|
||||
C++的多态分为静态多态(编译时多态)和动态多态(运行时多态)两大类。静态多态通过重载、模板来实现;动态多态就是通过本文的主角虚函数来体现的。
|
||||
|
||||
虚函数实现原理:包括虚函数表、虚函数指针等
|
||||
|
||||
虚函数的作用说白了就是:当调用一个虚函数时,被执行的代码必须和调用函数的对象的动态类型相一致。编译器需要做的就是如何高效的实现提供这种特性。不同编译器实现细节也不相同。大多数编译器通过vtbl(virtual table)和vptr(virtual table pointer)来实现的。 当一个类声明了虚函数或者继承了虚函数,这个类就会有自己的vtbl。vtbl实际上就是一个函数指针数组,有的编译器用的是链表,不过方法都是差不多。vtbl数组中的每一个元素对应一个函数指针指向该类的一个虚函数,同时该类的每一个对象都会包含一个vptr,vptr指向该vtbl的地址。
|
||||
|
||||
|
||||
|
||||
C/C++的具体总结可看[cpp-backend-reference/back-end.md at master · chankeh/cpp-backend-reference (github.com)](https://github.com/chankeh/cpp-backend-reference/blob/master/back-end.md)
|
||||
|
43
notes/Jenkins.md
Normal file
43
notes/Jenkins.md
Normal file
@ -0,0 +1,43 @@
|
||||
按Git的学习之旅的安排
|
||||
|
||||
# Jenkins简介
|
||||
|
||||
Java开发的开源软件--一定需要**jdk环境**
|
||||
|
||||
持续集成工具,用于监控持续重复的工作--假设没有Jenkins的话会怎样--**手动**build、**手动**部署?
|
||||
|
||||
官网: https://jenkins.io
|
||||
|
||||
# Jenkins的下载与安装
|
||||
|
||||
必须要java8。
|
||||
|
||||
jenkins.msi---Windows平台中,直接双击安装 ,比较方便。
|
||||
|
||||
jenkins.war---web项目,java -jar jenkins.war或直接放到tomcat等web容器的web-app下面,启动tomcat.
|
||||
|
||||
安装配置默认插件、配置等。
|
||||
|
||||

|
||||
|
||||
# Jenkins的工作流程
|
||||
|
||||
1. 如何帮助我们自动完成这些工作的呢---->Jenkins的工作流程
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
1.
|
||||
|
||||
2. 拉取代码机制
|
||||
|
||||
> 让Jenkins任务对应一个仓,到该拉取代码。
|
||||
|
||||
3. 项目构建与发布
|
||||
|
||||
|
||||
|
||||
4. 自动集成发布--不需要手动让Jenkins去拉取、构建和部署。
|
||||
|
||||
|
78
notes/Kubernetes.md
Normal file
78
notes/Kubernetes.md
Normal file
@ -0,0 +1,78 @@
|
||||
[TOC]
|
||||
|
||||
# Kubernetes
|
||||
|
||||
多节点之间的container管理 & 编排。
|
||||
|
||||
https://docs.docker.com/get-started/overview/
|
||||
|
||||
|
||||
|
||||
相同功能的有docker swarm、mesos。
|
||||
|
||||
## POD
|
||||
|
||||
一个或多个容器的最小操作单元
|
||||
|
||||
## ReplicaSet
|
||||
|
||||
通过一组字段。维护和管理POD。
|
||||
|
||||
may never need to manupulate ReplicaSet,use Deployment instead
|
||||
|
||||

|
||||
|
||||
## Label
|
||||
|
||||
标签和选择算符
|
||||
|
||||
## Service
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## node
|
||||
|
||||
Kubernetes中的工作节点。
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
kubectl: k8s集群的入口 创建poid 各种资源 kubectl ---> kubectl create pod nginx-pod --image=nginx:latest
|
||||
|
||||
master 认证授权: 对于整个k8s集群是否有操作权限,或者有什么样的权限
|
||||
|
||||
master节点 api server: 接受kubectl的命令,检查语法是否有错误,
|
||||
|
||||
scheduler: 调度, 判断w1\w2 …节点是否满足pod资源分配要求(带宽、内存、CPU)
|
||||
|
||||
> 说明: 集群中,master节点一般不承担创建业务的pod.系统pod一般都创建在master节点上。
|
||||
|
||||
|
||||
|
||||
## 搭建K8s集群
|
||||
|
||||
|
||||
|
||||
## K8s存储相关的内容及进阶
|
||||
|
||||
``` sh
|
||||
exportfs及exportfs -r
|
||||
|
||||
systemctl restart rpcbind & systemctl enable rpcbind
|
||||
|
||||
showmount
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
https://note.youdao.com/s/CPsWTGBI
|
||||
|
||||
CI/CD
|
||||
|
||||
Docker与Kubernetes
|
||||
|
@ -1063,6 +1063,38 @@ $ printf '%10s %5i %5i %5i %8.2f \n' $(cat printf.txt)
|
||||
是由 Alfred Aho,Peter Weinberger 和 Brian Kernighan 创造,awk 这个名字就是这三个创始人名字的首字母。
|
||||
|
||||
awk 每次处理一行,处理的最小单位是字段,每个字段的命名方式为:\$n,n 为字段号,从 1 开始,\$0 表示一整行。
|
||||
```sh
|
||||
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
|
||||
POSIX options: GNU long options: (standard)
|
||||
-f progfile --file=progfile
|
||||
-F fs --field-separator=fs
|
||||
-v var=val --assign=var=val
|
||||
Short options: GNU long options: (extensions)
|
||||
-b --characters-as-bytes
|
||||
-c --traditional
|
||||
-C --copyright
|
||||
-d[file] --dump-variables[=file]
|
||||
-D[file] --debug[=file]
|
||||
-e 'program-text' --source='program-text'
|
||||
-E file --exec=file
|
||||
-g --gen-pot
|
||||
-h --help
|
||||
-i includefile --include=includefile
|
||||
-l library --load=library
|
||||
-L[fatal|invalid|no-ext] --lint[=fatal|invalid|no-ext]
|
||||
-M --bignum
|
||||
-N --use-lc-numeric
|
||||
-n --non-decimal-data
|
||||
-o[file] --pretty-print[=file]
|
||||
-O --optimize
|
||||
-p[file] --profile[=file]
|
||||
-P --posix
|
||||
-r --re-interval
|
||||
-s --no-optimize
|
||||
-S --sandbox
|
||||
-t --lint-old
|
||||
-V --version
|
||||
```
|
||||
|
||||
示例:取出最近五个登录用户的用户名和 IP。首先用 last -n 5 取出用最近五个登录用户的所有信息,可以看到用户名和 IP 分别在第 1 列和第 3 列,我们用 \$1 和 \$3 就能取出这两个字段,然后用 print 进行打印。
|
||||
|
||||
@ -1098,6 +1130,16 @@ root 0
|
||||
bin 1
|
||||
daemon 2
|
||||
```
|
||||
示例: 过滤日志文件中返回码及其个数
|
||||
```sh
|
||||
awk -F"|" '{print $7}' /opt/logs/interface.log | sort | uniq -c | sort -nrk 1 | awk '{printf "返回码==%-10s , 返回码个数==%s\n",$2,$1}'
|
||||
|
||||
示例: 查询某指定文本日志文件中,根据某分隔符的第几个字段的值为指定值的文本在该文本日志件中的打印
|
||||
```sh
|
||||
grep "example" logfile.txt | awk -F',' '$2=="example" {print}'
|
||||
```
|
||||
> `grep "example" logfile.txt`:首先使用grep命令查找包含"example"的行,并将结果输出到标准输出。
|
||||
> `awk -F',' '$2=="example" {print}'`:然后使用awk命令对grep的输出进行处理。`-F','`指定分隔符为逗号。`$2=="example"`表示只处理第2个字段为"example"的行。`{print}`表示打印符合条件的行。
|
||||
|
||||
awk 变量:
|
||||
|
||||
@ -1117,6 +1159,18 @@ dmtsai lines: 3 columns: 10
|
||||
dmtsai lines: 4 columns: 10
|
||||
dmtsai lines: 5 columns: 9
|
||||
```
|
||||
[netstat命令和awk命令查看并发连接数](https://www.cnblogs.com/wayne173/p/5652043.html)
|
||||
```sh
|
||||
netstat -n|awk '/^tcp/ {++S[$NF]} END {for(a in S) print a,S[a]}'
|
||||
```
|
||||
|
||||
> 这个shell命令的作用是查看TCP连接状态的数量统计。
|
||||
>
|
||||
> 具体解释如下:
|
||||
>
|
||||
> 1. `netstat -n`:使用netstat命令查看网络连接状态,其中-n参数表示不将IP地址和端口号转换为对应的域名和服务名称,以便更快地输出结果。
|
||||
> 2. `|`:将netstat命令的输出结果通过管道符号传递给awk命令。
|
||||
> 3. `awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'`:使用awk命令对netstat命令的输出结果进行处理。 - `/^tcp/`:使用正则表达式匹配以tcp开头的行。 - `{++S[$NF]}`:对每个状态进行计数,使用数组S存储计数结果,其中$NF表示每行的最后一个字段,即TCP连接状态。 - `END {for(a in S) print a, S[a]}`:在处理完所有行后,使用for循环遍历数组S,输出每个TCP连接状态和对应的数量。 综上,该命令的输出结果将显示每个TCP连接状态的数量统计。
|
||||
|
||||
## 十、进程管理
|
||||
|
||||
|
@ -57,13 +57,14 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
|
||||
|
||||
## 二、数据类型
|
||||
|
||||
| 数据类型 | 可以存储的值 | 操作 |
|
||||
| :--: | :--: | :--: |
|
||||
| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作\</br\> 对整数和浮点数执行自增或者自减操作 |
|
||||
| LIST | 列表 | 从两端压入或者弹出元素 \</br\> 对单个或者多个元素进行修剪,\</br\> 只保留一个范围内的元素 |
|
||||
| SET | 无序集合 | 添加、获取、移除单个元素\</br\> 检查一个元素是否存在于集合中\</br\> 计算交集、并集、差集\</br\> 从集合里面随机获取元素 |
|
||||
| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对\</br\> 获取所有键值对\</br\> 检查某个键是否存在|
|
||||
| ZSET | 有序集合 | 添加、获取、删除元素\</br\> 根据分值范围或者成员来获取元素\</br\> 计算一个键的排名 |
|
||||
|
||||
| Redis值数据类型 | 底层数据结构 | 支持的操作命令 | 使用场景 |
|
||||
| ------------------------------ | ---------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| String 字符串 | | set key value/get key/del key | 对整个字符串或者字符串的其中一部分执行操作<br />对整数和浮点数执行自增或者自减操作 |
|
||||
| List 列表(可存在重复值) | | rpush list-key item/lpush list-key item/lrange list-key startIdx endIdx/lindex list-key idx/lpop list-key | 从两端压入或者弹出元素<br />对单个或者多个元素进行修剪<br /> 只保留一个范围内的元素 |
|
||||
| Set 集合(不存在重复,非有序) | | sadd set-key item/smembers set-key/sismember set-key item2 | 添加、获取、移除单个元素<br /> 检查一个元素是否存在于集合中<br /> 计算交集、并集、差集<br /> 从集合里面随机获取元素 |
|
||||
| Hash 散表列(键值对无序散列表) | 字典(两个dictht,使用拉链法解决冲突),rehash | hset hash-key sub-key1 value1/hgetall hash-key/hdel hash-key sub-key1 | 添加、获取、移除单个键值对<br />获取所有键值对<br />检查某个键是否存在 |
|
||||
| ZSET 有序集合 | 跳跃表 | zadd zset-key 728 member1/zrange zset-key startIdx endIdx withscores/zrangebyscrore zset-eky 0 800 withscores/zrem zset-eky member | 添加、获取、删除元素<br /> 根据分值范围或者成员来获取元素<br />计算一个键的排名 |
|
||||
|
||||
> [What Redis data structures look like](https://redislabs.com/ebook/part-1-getting-started/chapter-1-getting-to-know-redis/1-2-what-redis-data-structures-look-like/)
|
||||
|
||||
@ -552,6 +553,12 @@ def main():
|
||||
## 十二、Sentinel
|
||||
|
||||
Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务器。
|
||||
**监控(Monitoring)** 不间断检测Redis的运行状态.
|
||||
**提醒(Notification** 当监控的Redis出现问题时,通过API向管理员或者其他应用程序 发送通知.
|
||||
**自动故障迁移(Automatic failover** 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
|
||||
**协议** 流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移 。
|
||||
Redis主从复制 搭建
|
||||
https://gper.gupaoedu.com/articles/7e7e7f7ff5g5bgc3
|
||||
|
||||
## 十三、分片
|
||||
|
||||
|
385
notes/docker和kubernetes.md
Normal file
385
notes/docker和kubernetes.md
Normal file
@ -0,0 +1,385 @@
|
||||
[TOC]
|
||||
|
||||
|
||||
|
||||
# 发展历程
|
||||
|
||||
1. 早期的物理机
|
||||
|
||||
2. 虚拟化技术--虚拟机
|
||||
|
||||
3. 容器化docker -- 典型的C/S架构,Go语言开发(适合高并发),[hub.docker.com]()
|
||||
|
||||

|
||||
|
||||
```sh
|
||||
docker pull **
|
||||
docker push
|
||||
|
||||
docker run -d --name my-tomcat -p 9999:8080 tomcat:8.0
|
||||
docker stop **
|
||||
|
||||
docker version
|
||||
|
||||
docker images/docker ls
|
||||
# 取别名
|
||||
docker tag
|
||||
|
||||
docker ps
|
||||
docker rmi -f
|
||||
```
|
||||
|
||||
# Image深入讨论
|
||||
|
||||

|
||||
|
||||
在docker中任何一个image:tomcat\redis\mysql,其最底层就是一个最小内核的linux kernel.
|
||||
|
||||
github.com/docker-library
|
||||
|
||||
dockerfile:
|
||||
|
||||
> FROM debian: buster-slim
|
||||
>
|
||||
> RUN ...
|
||||
>
|
||||
> CMD [mysqld]
|
||||
|
||||
docker build [dockerFinleName] .
|
||||
|
||||
|
||||
|
||||
4. 自定义镜像怎么办?
|
||||
|
||||
tomcat、redis、mysql、rocketmq等中间件都已有官方写好了的镜像
|
||||
|
||||
根据image就可以创建出container
|
||||
|
||||
而且image是可以发给不同的人使用的,只要对应机器上安装了DockerEngine即可。
|
||||
|
||||
``` dockerfile
|
||||
FROM openjdk:8
|
||||
COPY dockerfile-demo-0.0.1-SNAPSHOT.jar jack-dockerfile-image.jar
|
||||
CMD ["java","-jar","jack-dockerfile-image.jar"]
|
||||
```
|
||||
|
||||
|
||||
|
||||
springboot项目-->image-->container
|
||||
|
||||
``` shell
|
||||
docker build -t jack-dockerfile-image .
|
||||
```
|
||||
|
||||
```sh
|
||||
docker run -d --name sb01 -p 6661:8080 jack-dockerfile-image
|
||||
```
|
||||
|
||||
```sh
|
||||
docker logs [容器名称]
|
||||
```
|
||||
|
||||
|
||||
|
||||
5. image共享给别人使用
|
||||
|
||||
* 需要创建一个镜像
|
||||
|
||||
* 上传到公共的仓库
|
||||
|
||||
* 当前本地需要登录一个公共仓
|
||||
|
||||
```shell
|
||||
sudo docker login -username=hqh registry.cn-hangzhou.aliyuncs.com
|
||||
```
|
||||
|
||||
|
||||
|
||||
* push到公共仓
|
||||
|
||||
``` sh
|
||||
docker push registry.cn-hangzhou.aliyuncs.com/jack-kubernetes/jack-dockerfile-image
|
||||
```
|
||||
|
||||
|
||||
|
||||
* 其它人拉取使用
|
||||
|
||||
``` sh
|
||||
docker pull registry.cn-hangzhou.aliyuncs.com/jack-kubernetes/jack-dockerfile-image
|
||||
```
|
||||
|
||||
|
||||
|
||||
*
|
||||
|
||||
|
||||
|
||||
# Container深入探讨
|
||||
|
||||

|
||||
|
||||
```sh
|
||||
docker exec -it my-tomcat bash
|
||||
cat /etc/issue
|
||||
```
|
||||
|
||||
能否将已修改的container打包成新的镜像,打包分享给其他人使用----可以。
|
||||
|
||||
```sh
|
||||
docker commit [tomcat03] [gupao-customized-tomcat-image]
|
||||
```
|
||||
|
||||
* container常见操作
|
||||
|
||||
```sh
|
||||
docker ps -aq
|
||||
docker rm -f conatiner
|
||||
docker exec -it 容器名
|
||||
docker commit
|
||||
# 查看docker占用CPU等资源情况
|
||||
docker stats
|
||||
# 可以设置container使用资源的上限
|
||||
docker run -d --memory 300M --name jack-tomcat-memory-limit tomcat:8.0
|
||||
docker run -d --cup-shareds 10 --name jack-tomcat-cpu-limit tomcat:8.0
|
||||
```
|
||||
|
||||
|
||||
|
||||
*
|
||||
|
||||
6. 为了资源隔离
|
||||
|
||||
* Linux已提供的支持
|
||||
|
||||

|
||||
|
||||
kernel.org/doc
|
||||
|
||||
* 怎样降低开发或运维人员使用这些技术的门槛--Linux Container(LXC)
|
||||
|
||||
linuxcontainers.org——依然有门槛,更多的还是针对 Linux运维人员,出发点:基于隔离出物理机的资源,为了快速搭建出一个物理机中的虚拟资源
|
||||
|
||||
——未面向app
|
||||
|
||||
docker 在LXC基础上提出了针对具体的app进行隔离解决方案,image,contaner.
|
||||
|
||||
bocker
|
||||
|
||||
*
|
||||
|
||||
# Doker数据持久化和网络
|
||||
|
||||
```sh
|
||||
docker volume ls
|
||||
# 自定义
|
||||
docker volume create 自定义volume名
|
||||
docker volume inspect [volume名称]
|
||||
docker volume rm -f *
|
||||
```
|
||||
|
||||
|
||||
|
||||
## volume数据持久化
|
||||
|
||||
VOLUME /var/lib/mysql,有了VOLUME关键字之后,将容器的/var/lib/mysql实际在对应hosthost上建一个相应目录(在/var/lib/docker/volumes/*下)。
|
||||
|
||||
```sh
|
||||
docker run -d --name hqh-mysql -p 3301:3306 -v hqh-mysql-volume:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=jack666 --privileged mysql:5.7
|
||||
```
|
||||
|
||||
|
||||
|
||||
bind的概念
|
||||
|
||||
- -v ~/shop:/usr/local/tomcat/webapps/shop ,少民volume这个层次面试。bind mounting
|
||||
|
||||
- 把目录和专门的服务器绑定。
|
||||
|
||||
## docker中的网络
|
||||
|
||||
https://landscape.cncf.io/?category=container-runtime&grouping=category
|
||||
|
||||
|
||||
|
||||
```sh
|
||||
# 本地网卡信息
|
||||
ls /sys/class/net
|
||||
ip a
|
||||
ip link
|
||||
|
||||
cd /etc/sysconfig/network-scripts
|
||||
ip addr add ip dev eth0
|
||||
systemctl restart network
|
||||
ipup eth0
|
||||
ipdown eth1
|
||||
|
||||
docker network ls
|
||||
```
|
||||
|
||||
不同namespace下的网络
|
||||
|
||||
```sh
|
||||
ip netns add ns1
|
||||
|
||||
ip netns add ns2
|
||||
ip netns add ns3
|
||||
ip netns list
|
||||
|
||||
ip nets delete ns3 delete ns3
|
||||
|
||||
ip netns exec ns1 ip a
|
||||
ip netns exec ns1 ifup lo
|
||||
|
||||
# 创建了veth-ns1和veth-ns2,并成对
|
||||
ip link add veth-ns1 type veth peer name veth-ns2
|
||||
# 将各自关联到对应命名空间中
|
||||
ip link set veth-ns1 netns1
|
||||
ip link set veth-ns2 netns2
|
||||
|
||||
ip netns exec ns1 ip addr add 192.168.0.11/24 dev veth-ns1
|
||||
ip netns exec ns2 ip addr add 192.168.0.12/24 dev veth-ns2
|
||||
|
||||
ip netns exec ns1 ip link set veth-ns1 up
|
||||
ip netns exec ns2 ip link set veth-ns2 up
|
||||
|
||||
ip netns exec ns1 ping 192.168.0.12
|
||||
```
|
||||
|
||||
veth pair: virtual ethernet pair,一个虚拟
|
||||
|
||||

|
||||
|
||||
### docker网络之bridge
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
通过veth-pair彼此之间的通信。
|
||||
|
||||
```sh
|
||||
docker network ls
|
||||
docker network inspect bridge
|
||||
# 也可以自定义网侧面
|
||||
docker network create --subnet=172.18.0.0/24 tomcat-net-name
|
||||
# 通过docker run命令
|
||||
docker run -d --name nginx01 -p 6061:80 --network tomcat-net-name
|
||||
|
||||
# 将网络添加下
|
||||
docker network connect tomcat-name-net tomcat2
|
||||
```
|
||||
|
||||
其它模式:none\network ls
|
||||
|
||||
各个namespace这间,是共享宿主机分配的带宽,还是分配固定的带宽?——
|
||||
|
||||
|
||||
|
||||
## 基于Docker搭建MySQL高可用集群
|
||||
|
||||
MySQL单机部署--会增加不可用风险,
|
||||
|
||||
实现MySQL高可用,搭建MySQL集群,-->伴随要解决数据一致性问题。
|
||||
|
||||
### PXC
|
||||
|
||||
Percona Xtradb Cluster,percona.com
|
||||
|
||||
多主方案+同步复制-->强一制性,
|
||||
|
||||
方法(1) 原生 pxc 依赖 一步步手动搭建
|
||||
|
||||
(2) docker image方式搭建
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
```sh
|
||||
# 获取pxc镜像,其实就相当于获取mysql镜像
|
||||
docker pull percona/percona-xtradb-cluster:5.7.21
|
||||
|
||||
# 设置网络
|
||||
docker network create -subnet=172.19.0.0/24 pxc-cluster-net bridge
|
||||
|
||||
# 数据持久化(后续让容器进行关联)
|
||||
docker volume create pxc-v1
|
||||
docker volume create pxc-v2
|
||||
docker volume create pxc-v3
|
||||
|
||||
# 创建容器
|
||||
docker tag percona/percona-xtradb-clustrer:5.7.21 pxc
|
||||
docker run -d --name=node1 -p 3301:3306 pxc -e MYSQL_ROOT_PASSWORD=hqh666 -v pxc-v1:/var/lib/mysql -e CLUSTER_NAME=PXC --net=pxc-cluster-net -e XTRBACKUP_PASSWORD=hqh666 pxc
|
||||
|
||||
docker run -d --name=node2 -p 3302:3306 pxc -e MYSQL_ROOT_PASSWORD=hqh666 -v pxc-v2:/var/lib/mysql -e CLUSTER_NAME=PXC --net=pxc-cluster-net -e XTRBACKUP_PASSWORD=hqh666 -e CLUSTER_JOIN=node1 pxc
|
||||
|
||||
|
||||
docker run -d --name=node3 -p 3303:3306 pxc -e MYSQL_ROOT_PASSWORD=hqh666 -v pxc-v3:/var/lib/mysql -e CLUSTER_NAME=PXC --net=pxc-cluster-net -e XTRBACKUP_PASSWORD=hqh666 -e CLUSTER_JOIN=node1 pxc
|
||||
```
|
||||
|
||||
InnoDB cluster: 一主多从
|
||||
|
||||
|
||||
|
||||
## docker compose【一步创建多个容器--单台】-->docker swarm/Meos/kubernetes【一步创建多个容器--多台】
|
||||
|
||||
(1)安装docker-compose
|
||||
|
||||
```shell
|
||||
sudo curl -L "https://github.com/docker/compose/release/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
```
|
||||
|
||||
|
||||
|
||||
(2)定义一个yaml文件
|
||||
|
||||
```yaml
|
||||
version: "3.9"
|
||||
# service <---->container
|
||||
services:
|
||||
# 第一个container名字
|
||||
web:
|
||||
# 本地 image Dockerfile
|
||||
build: .
|
||||
# -p 5000:5000
|
||||
ports:
|
||||
- "8000:5000"
|
||||
# 第二个container名字
|
||||
redis:
|
||||
image: "redis:alpine"
|
||||
|
||||
networks:
|
||||
app-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
|
||||
|
||||
(3)通过docker compose一键启动
|
||||
|
||||
```sh
|
||||
docker compose up
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 容器编排&容器管理
|
||||
|
||||
如果是docker单机环境,其实docker compose也就够用了
|
||||
|
||||
但是因为一台宿主机器资源毕竟有限,所以肯定是希望多台docker组成的集群环境,就需要一起管理容器。
|
||||
|
||||
Docker Swarm、Mesos、Kubernetes
|
||||
|
||||
* Docker Swarm
|
||||
|
||||
scheduler——调度、计算
|
||||
|
||||
network
|
||||
|
||||
health
|
||||
|
||||
discovery——manager要知道work node在哪,w-->信息注册到manager
|
22
notes/缓存.md
22
notes/缓存.md
@ -84,26 +84,35 @@ CDN 主要有以下优点:
|
||||
|
||||
## 四、缓存问题
|
||||
|
||||
### 缓存穿透
|
||||
### 缓存穿透(Cache Penetration)
|
||||
|
||||
指的是对某个一定不存在的数据进行请求,该请求将会穿透缓存到达数据库。
|
||||
指的是对某个一定**不存在的**数据进行请求,该请求将会穿透缓存到达数据库(即数据**既不在缓存,也不在数据库**,例如特异构造的攻击数据)。
|
||||
|
||||
解决方案:
|
||||
|
||||
- 对这些不存在的数据缓存一个空数据;
|
||||
- 对这类请求进行过滤。
|
||||
- 使用布隆过滤器(布隆过滤器--判断存在的不一定真存在,判断不存在的一定不存在;只支持增加操作,是一个位图)
|
||||
|
||||
### 缓存雪崩
|
||||
### 缓存雪崩(Cache Avalanche)
|
||||
|
||||
指的是由于数据没有被加载到缓存中,或者缓存数据在同一时间大面积失效(过期),又或者缓存服务器宕机,导致大量的请求都到达数据库。
|
||||
指的是由于****数据没有被加载到缓存中,或者缓存数据在同一时间大面积失效(过期),又或者缓存服务器宕机**,导致****大量的请求都到达数据库****。
|
||||
|
||||
在有缓存的系统中,系统非常依赖于缓存,缓存分担了很大一部分的数据请求。当发生缓存雪崩时,数据库无法处理这么大的请求,导致数据库崩溃。
|
||||
|
||||
解决方案:
|
||||
|
||||
- 为了防止缓存在同一时间大面积过期导致的缓存雪崩,可以通过观察用户行为,合理设置缓存过期时间来实现;
|
||||
- 为了防止缓存在同一时间大面积过期导致的缓存雪崩,可以通过观察用户行为,合理**设置缓存过期时间**来实现;
|
||||
- 为了防止缓存服务器宕机出现的缓存雪崩,可以使用分布式缓存,分布式缓存中每一个节点只缓存部分的数据,当某个节点宕机时可以保证其它节点的缓存仍然可用。
|
||||
- 也可以进行缓存预热,避免在系统刚启动不久由于还未将大量数据进行缓存而导致缓存雪崩。
|
||||
- 也可以进行**缓存预热,避免在系统刚启动不久由于还未将大量数据进行缓存而导致缓存雪崩**。
|
||||
|
||||
### 缓存击穿(Hotspot Ivalid)
|
||||
**热点数据缓存过期**。我们的业务通常会有几个数据会被频繁地访问,比如秒杀活动,这类被频地访问的数据被称为热点数据。
|
||||
|
||||
如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。
|
||||
解决方案:
|
||||
- 互斥锁方案,保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
|
||||
- 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;
|
||||
|
||||
|
||||
### 缓存一致性
|
||||
@ -307,4 +316,5 @@ public class LRU<K, V> implements Iterable<K> {
|
||||
- [缓存那些事](https://tech.meituan.com/cache_about.html)
|
||||
- [一致性哈希算法](https://my.oschina.net/jayhu/blog/732849)
|
||||
- [内容分发网络](https://zh.wikipedia.org/wiki/%E5%85%A7%E5%AE%B9%E5%82%B3%E9%81%9E%E7%B6%B2%E8%B7%AF)
|
||||
- [缓存一致性问题](https://xiaolincoding.com/redis/architecture/mysql_redis_consistency.html#%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E4%B8%A4%E4%B8%AA%E6%93%8D%E4%BD%9C%E9%83%BD%E8%83%BD%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9F)
|
||||
- [How Aspiration CDN helps to improve your website loading speed?](https://www.aspirationhosting.com/aspiration-cdn/)
|
||||
|
388
做题情况统计--软件编程知识与应用.md
Normal file
388
做题情况统计--软件编程知识与应用.md
Normal file
@ -0,0 +1,388 @@
|
||||
|
||||
|
||||
# 做题情况统计--软件编程知识与应用
|
||||
|
||||
| 编程规范理解与应用(JAVA) | 合计 | 总题数 | 正确答题数 | 正确率 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------ | ---------- | ------ |
|
||||
| 核心类库:掌握集合与泛型、多线程编程、反射相关规范 | 集合与泛型:规范相关; 并发与多线程:规范相关,ArrayList动态数组、Vector | 4 | 4 | 100.0% |
|
||||
| 代码风格:掌握命名、注释、代码格式规范 | 命名 | 1 | 1 | 100.0% |
|
||||
| 扩展类库**:掌握IO编程、日志、正则表达式、数据库编程、网络编程相关规范** | IO编程:规范相关; 数据库编程:规范相关; 序列化:规范相关 | 4 | 3 | 75.0% |
|
||||
| 语法知识:掌握变量、数据类型、表达式、控制语句、方法、面向对象、异常相关规范 | 面向对象:规范相关; 数据类型:规范相关 | 6 | 3 | 50.0% |
|
||||
|
||||
| 编程语言能力(JAVA) | 合计 | 总题数 | 正确答题数 | 正确率 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------ | ---------- | ------ |
|
||||
| **JVM**:理解Class格式与类加载过程,**掌握运行时数据区结构与定位方法**,**理解GC原理与常用GC回收器,了解JIT机制** | 运行时数据区; Class格式; JIT; GC; 类加载 | 10 | 8 | 80.0% |
|
||||
| 语法知识:深入理解变量、数据类型、表达式、控制语句、方法、面向对象、异常的语法特性 | 方法; 数据类型; 语法知识:深入理解变量、数据类型、表达式、控制语句、方法、面向对象、异常的语法特性; 异常体系; 控制语句 | 10 | 8 | 80.0% |
|
||||
| **性能优化**:掌握代码级性能优化方法,**理解JVM的性能调优方法** | 集合:性能相关; GC:性能相关; 性能优化:掌握代码级性能优化方法,理解JVM的性能调优方法; 方法:性能相关; 表达式:性能相关; 运行时数据区:性能相关; 控制语句:性能相关; IO编程:性能相关 | 8 | 4 | 50.0% |
|
||||
| 核心类库:熟练掌握集合与泛型、多线程编程、反射的实战用法 | 反射; 线程; 集合与泛型 | 6 | 3 | 50.0% |
|
||||
| 扩展类库:熟练运用IO编程、正则表达式、安全类库等重要类库,掌握数据库编程、网络编程。 | 正则表达式; IO编程; 数据库编程 | 4 | 1 | 25.0% |
|
||||
|
||||
|
||||
|
||||
# 题目回顾
|
||||
|
||||
1. 类加载的~~几个~~**7**个阶段:
|
||||
|
||||
> (1)加载(字节码转换为方法区的运行时存储结构)
|
||||
>
|
||||
> (2)验证( Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚机自身安全)
|
||||
>
|
||||
> (3)准备(为类变量--static修饰--的变量分配内存并设置初始值--方法区)
|
||||
>
|
||||
> (4)解析(将常量池的符号引用替换为直接引用)
|
||||
>
|
||||
> (5) 初始化(虚拟机执行类构造器的过程;**虚拟机会保证一个类的 <clinit>() 方法在多线程环境下被正确的加锁和同步**)
|
||||
>
|
||||
> (6)使用(类被创建实例并被使用--实例化是分配在堆中)
|
||||
>
|
||||
> (7)卸载(当类不再被使用时,JVM对其进行垃圾回收,并释放其占用的内存空间)
|
||||
>
|
||||
> 一般(2)到(4)这三个阶段又叫链接阶段。
|
||||
|
||||
* 类加载——双亲委派机制(如果一个类加载器收到了类加载请求,先看父类加载器能否加载,一直如此到顶端加载器判断能否加载,如果顶端可以加载,则顶端加载,如果不行,则本类加载器加载)
|
||||
|
||||
1) 类加载时,判断两个类是否是同一个类,除了要求它们的名字相同外,还要求加载它们的类加载器实例是同一个,只有两者同时满足的情况下,JVM才认为这两个class是相同的。
|
||||
|
||||
2)ClassLoader的loadClass方法加载不存在的类会抛ClassNotFoundException,并不是说返回NULL。
|
||||
|
||||
3)自定义类加载器实现**继承****ClassLoader**后**,重写了**findClass方法加载指定路径上的class;**
|
||||
|
||||
4)BoostrapClassLoader加载核心库类(%JAVA_HOME%/lib目录下的jar包和类或者被-Xbootclasspath参数指定的路径中的所有类)--它是用**原生代码(使用C++)**来实现的,**并非继承java.lang.ClassLoader**
|
||||
|
||||
5)Extension加载器加载%JRE_HOME%/lib/ext下的类和jar包,或者java.ext.dirs系统变量所指定的路径下的jar包,System加载器加载CLASSPATH环境指定路径的类,
|
||||
|
||||
6)AppClassLoadrer负载加载当前应用classpath下的所有jar包和类。
|
||||
|
||||
1.
|
||||
|
||||
2. jinfo,info 查看运行环境参数、查看JVM系统参数、命令行参数---**不能看内存**
|
||||
|
||||
3. **值不可变类型: Integer、String,在Java 8中,Integer缓存池的大小默认为-128~127。不可变类型有:Boolean, Byte, Character,Short, Double, Float, Integer, Long, String, BigDecimal**
|
||||
|
||||
4. 反射相关:
|
||||
|
||||
> * getType() 方法返回的是对象的运行时类型,即 Class 对象,而 getGenericType() 方法返回的是对象的泛型类型,即 Type 对象。
|
||||
>
|
||||
> * 具体来说,getType() 方法返回的是 Class 对象,它代表了对象的实际类型,例如 String、Integer、List 等。而 getGenericType() 方法返回的是 Type 对象,它代表了对象的泛型类型,例如 List<String>、Map<Integer, String> 等。
|
||||
>
|
||||
> 因此,getType() 方法只能获取对象的实际类型,而无法获取对象的泛型类型信息;而 getGenericType() 方法则可以获取对象的泛型类型信息,包括泛型参数的类型、数量等。
|
||||
|
||||
5. Java集合类
|
||||
|
||||
* ArrayList——当内部存储空间不够时,扩大50%。默认长度是10。
|
||||
|
||||
* Vector—— 当内部存储空间不够时,扩大1倍。默认长度是10。
|
||||
|
||||
* StringBuffer——默认长度是16
|
||||
|
||||
* StringBuilder——默认长度是16
|
||||
|
||||
* HashSet——默认长度是16
|
||||
|
||||
* HashMap——默认长度为16,允许key和value都为null
|
||||
|
||||
* HashTable——默认长度是11
|
||||
|
||||
* XxxBlockingQueue(array的要手工指定,linked默认是Integer.MAX_VALUE)
|
||||
|
||||
**线程安全的集合:**vector、hashtable、StringBuffer、ConcurrentMap(不可存放key和value都为null的对象)
|
||||
|
||||
非线程安全的集合: ArrayList、LinkeList(双队列)、HashMap、StringBuilder、LinkedHashSet、LinkedHashMap——保持了插入的顺序-->LRU、PriorityQueue
|
||||
|
||||
|
||||
|
||||
6. 重写与重载:
|
||||
|
||||
**重写(Override)**:
|
||||
|
||||
* 发生在**父子类**之间,方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常
|
||||
|
||||
* 重写的返回类型与被重写的返回类型可以不相同,但必须是父类返回值的派生类
|
||||
|
||||
* 声明为**final**或**static**的**方法**不能被重写
|
||||
|
||||
**重载(Overload)**
|
||||
|
||||
发生在同一个类中
|
||||
|
||||
|
||||
|
||||
7. 在java中关于抽象类的描述正确的是()
|
||||
|
||||
A、抽象类必须包含一个抽象方法 ——这个我很容易认为是对的,抽象类可以包含抽象方法,也可以包含非抽象方法
|
||||
|
||||
B、抽象类的方法必须是抽象的 ——这个我很容易认为是对的
|
||||
|
||||
C、声明抽象类必须带有abstract ——这个我很容易认为是错的
|
||||
|
||||
D、抽象类可以被实例化 —— 这个显然错误。抽象方**法必须在子类**中被实现。**抽象类的声明必须带有abstract关键字**。主要作用是**为了被其他类继承**。
|
||||
|
||||
interface中的属性的默认修饰权限:public static final,方法属性:public abstract
|
||||
|
||||
8. JVM:
|
||||
|
||||
以下程序运行结果如何,micro.yam文件不存在。
|
||||
|
||||
考察异常类及其继承关系:
|
||||
|
||||
```
|
||||
/**
|
||||
* 科目二 题目,如代码,程序运行结果如何:
|
||||
* A、文件路径, finish
|
||||
* B、ooo,打印异常堆栈,finish
|
||||
* C、ooo,打印异常堆栈
|
||||
* D、直接抛出类加载异常
|
||||
*
|
||||
* @author h00284904
|
||||
* @since 2021-09-27
|
||||
*/
|
||||
public class JVM_FileParse_Verify {
|
||||
public static final String A = JVM_FileParse_Verify.class.getClassLoader().getResource("micro.yam").getPath();
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
System.out.println(JVM_FileParse_Verify.A);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("ooo");
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("finish");
|
||||
// Exception in thread "main" java.lang.ExceptionInInitializerError
|
||||
// Caused by: java.lang.NullPointerException
|
||||
// at com.huawei.hqh.JVM_FileParse_Verify.<clinit>(JVM_FileParse_Verify.java:14)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
因为A就在主类中,且是静态,所在调用main之前就已抛出异常
|
||||
|
||||
```
|
||||
package com.huawei.hqh;
|
||||
|
||||
class JVM_FileParser {
|
||||
public static final String A = JVM_FileParser.class.getClassLoader().getResource("micro.yam").getPath();
|
||||
}
|
||||
/**
|
||||
* 功能描述
|
||||
*
|
||||
* @author h00284904
|
||||
* @since 2021-09-28
|
||||
*/
|
||||
public class JVM_FileParser_Verify2 {
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
System.out.println(JVM_FileParser.A);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("ooo");
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println("finish");
|
||||
}
|
||||
//ooo
|
||||
// java.lang.ExceptionInInitializerError
|
||||
// at com.huawei.hqh.JVM_FileParser_Verify2.main(JVM_FileParser_Verify2.java:15)
|
||||
// Caused by: java.lang.NullPointerException
|
||||
// at com.huawei.hqh.JVM_FileParser.<clinit>(JVM_FileParser_Verify2.java:4)
|
||||
// ... 1 more
|
||||
//finish
|
||||
}
|
||||
```
|
||||
|
||||
9. 线程:
|
||||
|
||||
java 中断线程, 下面哪些情况可能导致中断当前线程的运行? (A、B、D)
|
||||
|
||||
A. 抛出一个异常
|
||||
|
||||
B. 当前线程调用wait()方法等待竞争资源
|
||||
|
||||
C. 当前线程创建一个新线程时
|
||||
|
||||
D. 当前线程调用sleep()方法时
|
||||
|
||||
https://zhuanlan.zhihu.com/p/149205707
|
||||
|
||||
https://www.cnblogs.com/paddix/p/5381958.html
|
||||
|
||||
10. **类文件**:
|
||||
|
||||
ClassFile {
|
||||
|
||||
u4 magic; ——固定为“0xCAFEBABE”,作用是确定该文件为一个可被JVM加载的Class文件。
|
||||
|
||||
u2 minor_version; ——Class文件的副版本
|
||||
|
||||
u2 major_version; ——Class文件的主版本
|
||||
|
||||
u2 constant_pool_count;
|
||||
|
||||
cp_info constant_pool[constant_pool_count-1];
|
||||
|
||||
u2 access_flags;
|
||||
|
||||
u2 this_class;
|
||||
|
||||
u2 super_class;
|
||||
|
||||
u2 interfaces_count;
|
||||
|
||||
u2 interfaces[interfaces_count];
|
||||
|
||||
u2 fields_count; field_info fields[fields_count];
|
||||
|
||||
u2 methods_count; method_info methods[methods_count];
|
||||
|
||||
u2 attributes_count; attribute_info attributes[attributes_count];
|
||||
|
||||
}
|
||||
|
||||
其中,u1、u2、u4分别代表1、2、4个字节无符号数。
|
||||
|
||||
说明:
|
||||
javac -g TestClass.java-g:生成所有的调试信息,包括局部变量名和行号信息。
|
||||
javap -c TestClass > TCC.txt,
|
||||
|
||||
对于javap常用的参数:-c:输出字节码Code-l(小写L):输出Code、LineNumberTable与LocalVariableTable-s:输出方法签名(方法的接收参数列表和返回值)-verbose:包含-c、-l以及输出class文件的编译版本,常量池,Stack, Locals, Args_size对于javap而言,常用的就是-c或-verbose
|
||||
作者:徐家三少
|
||||
链接:https://juejin.cn/post/6844903464481325064
|
||||
|
||||
11. **泛型**使用之PECS(Producer Extends Consumer Super)原则:**当只想从集合中获取元素,请把这个集合看成生产者,请使用<? extends T>,这就是Producer extends原则,PECS原则中的PE部分。**
|
||||
|
||||
**泛型与PECS:https://www.jianshu.com/p/e5b8cd33ec94?u_atoken=b39aa8a6-b196-4d41-9782-7c25662c0cc9&u_asession=01BjCr_1l-lFSEGUHFjg5OsLL3pscZ9J7HCTj7CD9shJSrg_xVl5cUdEmfKxgML9ipX0KNBwm7Lovlpxjd_P_q4JsKWYrT3W_NKPr8w6oU7K-eTQ6hLYwsFz-l_HWOSEkocCO_LNVcRl1Qbia_a5plzmBkFo3NEHBv0PZUm6pbxQU&u_asig=05WsD83ID0Tr7mSzPvQnLSMC7_9WEyYVY8Q0d4iFV0VaqFLtDNGi6xzsFcPbJg6RBo-VQeq2NrTZ_RTkeuVVUtppPLivPJBTV_CPH31hd3Lk9XVuwQ6ImA-4GrwQ-pYJgYvCAChf9--VSC925Oa2ydvUzNZFdNwYN16nMxAeCwSH39JS7q8ZD7Xtz2Ly-b0kmuyAKRFSVJkkdwVUnyHAIJzQhDv5RpUbAmToYFDMC0YyH-SIxHNXAMYgQIJs2NKSYja2GRgmoIOFBw7FYOdgQIyu3h9VXwMyh6PgyDIVSG1W_ladG6YsfXrB7slA80ltmTMcP86Dpk-9o5WW2hT6bxqq2XrK0uO2qG0zzYpsjVKEj0v_O4rXVVATYuGBfXtkIFmWspDxyAEEo4kbsryBKb9Q&u_aref=Q%2BYoK3NQIQx85iMjzFEOmRFHgdc%3D**
|
||||
|
||||
总结PECS原则如果你只需要从集合中获得类型T , 使用<? extends T>通配符如果你只需要将类型T放到集合中, 使用<? super T>通配符如果你既要获取又要放置元素,则不使用任何通配符。例如List<Apple>PECS即 Producer extends Consumer super, 为了便于记忆。(《effective java》第28条)为何要PECS原则?你还记得前面提到泛型是不可变(**协变、逆变、不变**概念)吗?即List<Fruit>和List<Apple>之间没有任何继承关系。API的参数想要同时兼容2者,则只能使用PECS原则。这样做提升了API的灵活性。
|
||||
在java集合API中,大量使用了PECS原则,例如java.util.Collections中的集合复制的方法:`public static <T> void copy(List<? super T> dest, List<? extends T> src) { ... } `集合复制是最典型的用法:复制源集合src,主要获得元素,所以用<? extends T>复制目标集合dest,主要是设置元素,所以用<? super T>**当然,为了提升了灵活性,自然牺牲了部分功能。鱼和熊掌不能兼得。**补充说明这里的错误全部是编译阶段不是运行阶段,编译阶段程序是没有运行。所以不能用运行程序的思维来思考。使用泛型,就是要在编译阶段,就找出类型的错误来。
|
||||
作者:安静的猫咪先生
|
||||
链接: https://www.jianshu.com/p/e5b8cd33ec94
|
||||
|
||||
12. 考察**NIO**:
|
||||
|
||||
要从文件中读出第10个字节—FileInputStream,与FileChannel关系等
|
||||
|
||||
readAllLines
|
||||
|
||||
哪些**不属于**NIO的buffer: StringBuffer,CharBuffer,IntBuffer,FloatBuffer
|
||||
|
||||
skip(9),
|
||||
|
||||
13. **Netty**的高性能体现在哪?ABCDE
|
||||
|
||||
A、非阻塞IO
|
||||
|
||||
B、内存零拷贝
|
||||
|
||||
C、内存池
|
||||
|
||||
D、串行化处理读写
|
||||
|
||||
E、高性能序列化协议
|
||||
|
||||
解读 Netty的高性能表现:
|
||||
|
||||
(1)IO线程模型:**同步非阻塞**,用最少的资源做更多的事情?何解
|
||||
|
||||
(2)内存零拷贝:尽量减少不必要的内存拷贝,实现了更高效率的传输
|
||||
|
||||
(3)内存池设计:申请的内存可以重用,主要指直接内存。内部实现是通过一棵二叉查找树来管理内存分配情况。
|
||||
|
||||
(4)串行化处理读写:避免使用锁带来的性能开销。即消息的处理尽可能在同一个线程内完成,期间不进行线程切换,这样避免了多线程竞争和同步锁。表面上看,串行化设计似乎CPU利用率不高,并发程度不够。但是,通过调整NIO线程池的线程参数,可以同时启动多个串行化的线程并行运行,这种局部无锁化的串行线程设计相比一队列里多个工作线程模型性能更优。
|
||||
|
||||
(5)高性能序列化协议:支持ProtoBuf等高性能序列化协议
|
||||
|
||||
(6)高效并发编程的体现:volatile的大量、正确使用; CAS和原子类的广泛使用;线程安全容器的使用;通过读写锁提升并发性能。
|
||||
|
||||
14. 关于**Java8 Stream**的描述正确的是: **Stream跟迭代器类似,再次遍历需要重新生成。**
|
||||
|
||||
Stream的特点:
|
||||
|
||||
1) 无存储,Stream不是一种数据结构,也不保存数据,数据源可以是数组、容器、I/O或Channel等;
|
||||
2) 为函数式编程而生,对Stream的任何修改都不会修改数据源;
|
||||
3) 惰性执行,Stream上的中间操作并不会立即执行,只有等到用户真正需要结果时才会执行;
|
||||
4) 一次消费,Stream只能被消费一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成
|
||||
|
||||
|
||||
|
||||
15. 字符流 和 字节流:
|
||||
|
||||
* **字节流**的基类**InputStream/OutputStream**,**字符流**是**Reader/Writer**
|
||||
* 字符流最终都会按照字节流处理
|
||||
|
||||
16. Optional——主要用来处理每个程序员都会碰到的空指针异常问题,Java9还补充了or()、IfPresentOrElse()及stream()。属于可选值的封装类,即可以为空,也可以包含对象。
|
||||
|
||||
关于java optional参照 https://www.jianshu.com/p/63830b7cb743
|
||||
|
||||
17. **Java 本地方法**的正确定义:"它一般在本地声明,异地用C和C++来实现。它的声明有几点要注意:1)native与访问控制符前后的关系不受限制。2)必须在返回类型之前。3)它一般为非抽象类方法。4)native方法在异地实现,象抽象方法一样,所以没有方法体,以分号结束。如下列5种声明: native public void f(); 正确。
|
||||
private native void f(); 正确。
|
||||
protected int native f(); 错误,返回类型位置不对,返回类型必须在native之后。
|
||||
public abstract native void f(); native必然不是abstract的。
|
||||
native int f(){} 错误,因为存在方法体{}
|
||||
public static native f(); 正确。static与native方法位置随意。"
|
||||
|
||||
可参照 https://blog.csdn.net/x_panda/article/details/17120479
|
||||
|
||||
18. **正则表达式**
|
||||
|
||||
正则表达式/a+(bab)?(caac)*/,下列选项中该正则表达式的子集是?A
|
||||
|
||||
A. /a{2} B. /a+(bab){0,1}(ca)+(ca)/ C. /(bab)(caca)/ D. /a(bab){2}(caac)*/
|
||||
|
||||
FutureTask : https://pdai.tech/md/java/thread/java-thread-x-juc-executor-FutureTask.html
|
||||
|
||||
19. 加解密
|
||||
|
||||
**推荐使用的对称加密算法有: AES**
|
||||
|
||||
**推荐使用的非对称算法有: RSA 推荐使用的数字签名算法有: DSA ECDSA**
|
||||
|
||||
20. 若程序中要获取当前操作系统登录的用户名,应采用如下哪种方法?()
|
||||
|
||||
A、提示用户输入
|
||||
|
||||
B、由环境变量获取:System.getEnv('USER')
|
||||
|
||||
C、由JVM获取:System.getProperty('user.name')
|
||||
|
||||
D、启动程序的时候,由程序输入参数输入
|
||||
|
||||
从安全考虑和正确性考虑,A和D不行,我错误的选了B,但查规范,没有这样用的,直接获取“USER”,而且B也与操作系统相关。看来答案应该是C,JVM屏蔽了操作系统细节,且规范文档中倒是其它例子有用到。
|
||||
|
||||
|
||||
|
||||
http://ilearning.huawei.com/edx/subportal/portal/tseacademy?tab_name=tsea-software-development
|
||||
|
||||
21. 安全编程规范
|
||||
|
||||
| 序号 | 类型 | 提要 |
|
||||
| ---- | --------------- | ------------------------------------------------------------ |
|
||||
| 1 | 安全目标 | 机密、完整、可用 |
|
||||
| 2 | 不可信数据 | 文件、注册表、网络、环境变量、命令行、用户输入、用户态数据、进程间通信、函数参数、全局变量 |
|
||||
| 3 | 可信数据校验 | 1、标准(文件路径)、归一(NFD编码 或 字符串java.text.Normalizer.normalize()/Normalizer.Form.NFKC) 2、输入正则清理,不推荐断言 3、黑白校验 4、输出脱敏 |
|
||||
| 4 | SQL注入 | RDBMS:SQL注入(绕过检查、篡改数据、探测数据库结构、控制系统) 1、注入案例 ●没有引号,直接拼接字段的(拼接字段如果强转int可避免注入,但强转会出异常) ●order by 后拼接sql的 ●仅校验数据长度无效 2、措施 1、参数化预编译,重复调用效率高,推荐 (拼接后再预编译也可导致注入) 1.1、myBatis '$key$'替换**可注入**,#key#不可注入 1.2、存储过程也可注入 2、输入黑白校验 (黑、白并非推荐,无特殊要求时可优先考虑白) 3、转码,仅针对引号限制字段 |
|
||||
| 5 | OS注入 命令注入 | OS注入(Dos攻击、篡改数据,隐藏恶意活动) 1、使用jdk的API、输入校验、转码(推荐,对参数注入无效) 2、使用&拼接命令注入,Runtime.exec()避免shell方式执行,Runtime.loadLibrary(用户输入)可能导致注入 3、ping.exe后的均为参数 4、目录遍历攻击,getCanonicalPath()替代getAbsolutePath() 5、POSIX下可使用exec,建议使用WIN32 API CreateProcess 6、外部输入禁止特殊字符对命令注入无效 |
|
||||
| 6 | XML | 白名单、安全xml库(如dom4j)、转码 1、XXE(外部实体注入) 1.1、危害: ●获取服务端数据:<!ENTITY xxe SYSTEM "file:///etc/passwd" >]> ●探测内部网络:<!ENTITY xxe SYSTEM "https://192.168.1.1/private" >]> ●引用无限文件DOS <!ENTITY xxe SYSTEM "file:///dev/random" >]> 1.2、措施【entities限定 或 重写 的都是XXE】 ●禁止包含实体 .setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);//DOCTYPE ●禁止使用外部实体和参数实体.setFeature("http://xml.org/sax/features/external-general-entities", false); .setFeature("http://xml.org/sax/features/external-parameter-entities", false); ●覆写解析器解析实体的方法 XMLReader resolveEntity(String publicId, String systemId) ●提取实体内容校验 <!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC 2、XML内部实体扩展攻击:消耗目标程序的服务器内存 2.1、措施 ●禁止包含实体 setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);// XXE通用 ●限制实体解析个数 【数目限定的都是内部,对XXE无效】 dbf.setAttribute(“http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit”,“200”); System.setProperty(“entityExpansionLimit”, “200”); factory.setFeature(“http://javax.xml.XMLConstants/feature/secure-processing”, true); 3、XML注入/xPath注入:未对输入做管控,片段插入,非实体攻击 4、防止注入要从外部数据源头开始校验,拼接完成的xml已无校验意义 |
|
||||
| 7 | XSLT | 使用不安全的XSLT转换XML: 同上secure-processing |
|
||||
| 8 | 正则注入 | ReDos攻击、敏感信息泄露,不包含CSRF跨站请求构造(输入校验无法防止) 1、措施 ●输入长度限制 ●减少分组使用量 ●避免动态正则 ●Possessive Match会阻止正则表达式引擎尝试。推荐 ●白名单检查 |
|
||||
| 9 | zip文件解压 | 1、危害 ●文件解压到目标路径之外 ●解压文件消耗过多的系统资源 2、措施 ●调用sanitzeFileName()函数检查文件名称中是否存在路径遍历类问题 ●边读边统计实际解压文件大小及文件数量(不能使用entry.getSize()进行判断) |
|
||||
| 10 | 日志注入 | 1、日志伪造风险 ●使用白名单对不可信数据进行校验,禁止输入\r\n等换行符,\r\n替换_等,防止日志伪造 ●对不可信数据的长度进行限制 2、隐私/敏感数据的风险(直接使用log.info(XXX)) ●避免任意记录外部输入等不可信数据 ●只有明确为非敏感的数据才可以记录日志中 ●敏感信息用长度固定的*替代 注意: 1、记录日志时,不要主动抛出异常 |
|
||||
| 11 | 敏感异常 | java.io.FileNotFoundException 底层文件系统结构、文件名列举 java.sql.SQLException 数据库结构、用户名列举 java.net.BindException 非信任客户端可选择服务器端口时可枚举开放端口 java.util.ConcurrentModificationException 可能提供线程非安全代码的相关信息 javax.naming.InsufficientResourcesException 服务器资源不足(可能辅助DoS攻击) java.util.MissingResourceException 资源列举 java.util.jar.JarException 底层文件系统结构 java.lang.OutOfMemoryError DoS攻击 java.lang.StackOverflowError DoS攻击 java.security.acl.NotOwnerException 所有者枚举 注意: 1、转化为简洁的提示信息,抛出非敏感异常 2、异常不作为业务流程控制 |
|
||||
| 12 | 序列化 | 1、将包含敏感的字段声明为transient来实现 2、通过自定义writeObject()、writeReplace()、writeExternal()这些方法,不将包含敏感信息的字段写入序列化字节流中。 3、对敏感数据先签名再加密[注意顺序] (同一信任域中可直接传递) 4、禁止type功能包含实体 5、推荐使用Xstream组件 替代 XMLDecoder,XStream.setupDefaultSecurity(xst); 6、Java的反序列化操作,可以绕过对象构造函数的执行,但输入数据不能由外部输入指定 |
|
||||
| 13 | 线程同步 | 1、使用私有不变对象锁(private lock object idiom),使得攻击者无法获取到锁对象 2、基础数据类型如Boolean.FALSE、10、“LOCK”(或intern())等作为锁对象使用时,这些锁对象可被其他线程或功能重用 private final Integer lock = new Integer(count); private final String lock = new String("LOCK"); 3、防止使用getClass()返回的类对象进行同步,应该使用明确的锁对象。 4、private final Lock lock = new ReentrantLock();不要和synchronized(内置锁)混用 5、防止使用实例锁来同步共享静态变量 private static final Object lock = new Object(); 6、关键字 volatile变量可见 synchronized内置锁 7、自增自减不安全,AtomicInteger安全 |
|
||||
| 14 | 死锁 | 1、异常时未释放锁 2、请求锁和释放锁顺序不当 3、在阻塞操作中持有锁(如误用proc.waitFor()) 注意: 1、同步方法或使用对象内置锁的同步代码块中,直接抛出异常,不会死锁 |
|
||||
| 15 | IO | 1、临时文件使用完毕应及时删除,流在finally关闭而非try 2、不要将Buffer对象封装的数据暴露给不可信代码:如wrap()、slice()、duplicate(),应使用asReadOnlyBuffer(); 3、正确处理进程的输出流/错误流 .getErrorStream() .getInputStream() 4、创建文件指定访问权限,避免操作共享目录文件 5、Process.getOutputStream() 输出流可给外部程序提供输入;Process.getInputStream() 输入流可接受外部程序输入 |
|
||||
| 16 | 平台安全 | 1、声明为private或final的方法,可以防止被子类进行覆写 2、编写自定义类加载器时必须调用超类的getPermission()函数,强改jdk版本提示java.security.AccessContrlException:access denied 3、使用强随机数, java.security.SecureRandom 替代 java.util.Random(适用:随机选取路由) ●SessionID的生成(web应用会话) ●挑战算法中的随机数生成 ●验证码的随机数生成 ●生成重要随机文件的文件名 ●生成密钥相关的随机数生成 4、使用SSLSocket代替Socket,服务器通常都被认证(依赖服务端校验),如果服务器有要求,客户端也可以被认证 5、获取操作系统登录用户名: JVM System.getProperty("user.name") 替代OS环境变量获取 6、自动签名认证机制使用JAR文件中公钥验签,无法保证公钥签名恶意篡改,需要额外的检查 7、不能从配置文件中读取明文密码 8、所有安全敏感的代码可放在一个jar包中 9、jmxremot.port=XXXX不要开启,-Xveriy:none不要禁用JVM的字节码验证 10、安全检查:改权限/密码,删日志; 不需要检查的:记录日志 |
|
||||
| 17 | 编码 | 1、编码encoder注意防御:XSS、SQL注入 2、硬编码指令可直接作为exec()等入参 3、使用<>比较基础数据值替代=/!=,防止异常时数值为负 4、内部类要么是static的,要么就不要实现接口 |
|
||||
| 18 | 加密 | 1、不安全的加密算法: 分组加密DES、 哈希算法MD5 2、推荐的对称密码算法 AES, 非对称加密 RSA |
|
||||
|
||||
22. 开发者测试
|
||||
|
||||
| 序号 | 类型 | 提要 |
|
||||
| ---- | ------------ | ------------------------------------------------------------ |
|
||||
| 1 | DT基础概念 | 1、UT(功能/函数单元测试,注重黑盒测试,关注的是功能、接口,可以DevOps中CI门禁)、IT(集成测试)、ST(系统/子系统测试) |
|
||||
| 2 | DT测试设计 | 1、根据需求为达到性价比的测试设计,设计测试用例+;<br /> 2、测试要识别因子、因子值、方法。因子值要归类——等价类划分、边界; <br /> 因子值组合设计测试用例——AC(全排列组合,测试用例个数=各个因子的取值个数相乘) <br /> BC(基础组合,测试用例个数=**各个因子的取值个数相加 - 因子个数 + 1** ) <br /> EC(Each Comosite, 测试用例个数=最多因子值的因子值个数) |
|
||||
| 3 | 测试基础框架 | ( http://ilearning.huawei.com/edx/next/micro/course-v1:HuaweiX+CNE202007271113018-242+microcourse?blockID=8b4313d932774f83b749e38abaca493f ) <br />Java测试基础框架——Junit,是Xunit中的实例:<br />Maven框架,Junit4.11及以上。一般流程为:(1)数据准备;(2)调用函数(测试);(3)断言 <br />@Test ,函数命名一般为when…then… <br />高级断言——assertThat,统一了API,包括is\not\allof\anyof\… <br />Fixture——BeforeClass->RunWith->Before->TestMethod—>After->AfterClass <br />异常测试——(1)Try/Catch中要有断言;(2)assertThrow (3)@Test ExceptedException (4)@Test Except <br />超时——由于测试用例要满足F.I.R.S.T,其中Fast要求不能一直超时阻塞,@Test(timeout=X milliseconds)——适用于方法; @ Rule public Timeout globalTimeout = Timeout.seconds(3) <br />异常忽略说明——@Ignore(String description) <br />Junit4 参数化查询——{(输入,输出),},@RunWith(Parameterized.class) <br /> Junit 进阶优化——Rules : @Rule, Suite:把目前用例都归档 <br />Java测试框架——Mockito: |
|
||||
|
||||
23. Java程序调试
|
||||
|
||||
http://ilearning.huawei.com/edx/courses/course-v1:HuaweiX+CNE050000006949+Self-paced/courseware/46151a32eb0e49969a4ab2da6e3f2a56/a181bd2cd9c145509d9434fbc02a1f39/?child=first
|
||||
|
||||
24.
|
||||
|
2099
算法--九阳神功.md
Normal file
2099
算法--九阳神功.md
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user