精华内容
下载资源
问答
  • 背景 由于政策的要求,我们的应用系统需要过信息系统安全等级保护第三...所以与阿里云相关(物理安全、中间件安全)的测评需要重复进行,只需要提供阿里云的三级等保测评报告就可以。因此我们的三级等保测...

    背景

    由于政策的要求,我们的应用系统需要过信息系统安全等级保护第三级(简称三级等保)。在编写本文时,我们的三级等保已经通过,所以本文是对三级等保测评的一次总结。分享给大家,希望能够帮助有需要的人。

    我们的应用系统是基于阿里云部署的,阿里云作为云平台,本身通过了三级等保测评。所以与阿里云相关(物理安全、中间件安全)的测评都不需要重复进行,只需要提供阿里云的三级等保测评报告就可以。因此我们的三级等保测评可以转化为:阿里云三级等保报告+应用系统测评+安全管理规范三部分内容。本文着重对应用系统的测评要求进行描述。

    一、应用系统测评要求

    1、登录校验

    使用账号+静态密码+4位验证码进行登录验证。

    2、密码复杂度

    八位以上,大小写+特殊字符+数字,加盐,采用两次md5加密。

    3、密码更换

    要求用户密码每3个月更换一次,更新的口令5次内不能重复。

    4、登录失败策略

    当日连续登录失败 5 次则锁定账户,第二天再登录。登录成功则清空失败次数。

    5、退出

    提供退出功能,由用户主动操作退出系统。

    6、超时退出

    提供超时退出功能,在指定的时间后,系统自动退出。

    7、并发会话限制

    对单个帐户的多重并发会话进行限制,禁止同一用户同时登录系统。

    8、访问控制

    对系统中的每个请求资源进行权限控制,只有用户该权限的用户才可以访问资源,禁止越权操作。

    9、权限分离

    信息系统根据业务需求划分不同角色(管理员、审计员、业务员),应根据最小原则进行授权,对特权用户进行权限分离,实现各用户间形成相互制约关系,如录入与审核分离,操作与监督分离等。

    10、数据有效性校验

    在数据输入界面提供数据有效性检验功能。

    11、审计功能

    对系统的重要安全事件(包括用户登陆、用户注册、重要业务数据操作等行为)进行记录,形成审计日志。审计日志包括事件发生的日期和时间、触发事件的主体、事件的类型、事件成功或失败、事件请求的来源、事件的结果等,并提供导出功能。
    审计日志由审计员进行操作,其他人员无法操作。禁止提供修改、删除审计日志的功能,禁止提供终端审计进程的功能。

    12、HTTPS通信

    采用HTTPS加密通信方式对数据通信完整性进行保护。

    13、并发数控制

    对应用系统的并发数进行限制,超出限制后应进行报警通知。

    14、系统相关文档

    需求说明文档、概要设计文档、详细设计文档、用户手册等。

    15、安全防护

    通过购买阿里云安全组件或者自主安装的方式实现安全防护。包括ECS服务器、负载均衡器、云数据库RDS、云堡垒机、WEB应用防火墙、云盾证书、clamav(防病毒)等。

    二、安全管理规范

    包含安全管理制度、安全管理机构、人员安全管理、系统建设管理、系统运维管理等。

    三、参考资料

    GBT 22239-2008 信息安全技术 信息系统安全等级保护基本要求.pdf

    文章内容仅代表个人观点,如有不正之处,欢迎批评指正,谢谢大家。

    展开全文
  • 总结java高级面试题

    万次阅读 多人点赞 2019-05-10 16:25:39
    在JVM启动时或者在类运行时将需要的class加载到JVM中。 类加载时间与过程: 类从被加载到虚拟机内存开始,在到卸载出内存为止,正式生命周期包括了:加载,验证,准备,解析,初始化,使用和卸载7个阶段。其中...

    jvm结构原理,GC工作原理

    Jvm结构:

                       

    Jvm主要包括四个部分:

    1、类加载器(ClassLoad)

    在JVM启动时或者在类运行时将需要的class加载到JVM中。

     

    类加载时间与过程:

    类从被加载到虚拟机内存开始,在到卸载出内存为止,正式生命周期包括了:加载,验证,准备,解析,初始化,使用和卸载7个阶段。其中验证、准备、解析这个三个步骤被统称为连接(linking)。

                                           

    其中,加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的   ,类的加载过程必须按照这种顺序按部就班的“开始”(仅仅指的是开始,而非执行或者结束,因为这些阶段通常都是互相交叉的混合进行,通常会在一个阶段执行的过程中调用或者激活另一个阶段),而解析阶段则不一定(它在某些情况下可以在初始化阶段之后再开始,这是为了支持java语言的运行时绑定)

     

    在以下几种情况下,会对未初始化的类进行初始化:

    1. 创建类的实例
    2. 对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化
    3. 当初始化一个类的时候,发现其父类没有被初始化,则需要先初始化父类
    4. 当虚拟机启动的时候,用户需要指定一个执行的主类,虚拟机会先初始化这个主类

     

    类实例化和类初始化是两个不同概念:

    类实例化:是指创建一个类的实例对象的过程

    类初始化:是指类中各个类成员(被static修饰的成员变量)赋初始值的过程,是类生命周期的一个过程

     

    ClassLoader的等级加载机制

     

    Java默认提供的三个ClassLoader

    BootStrap ClassLoader:被称为启动类加载机制,是Java类加载层次中最顶层的类加载器,负责加载JDK中核心类库。

    Extension  ClassLoader:被称为扩展类加载器,负责加载Java的扩展类库,Java虚拟机的实现会提供一个扩展目录,该类加载器在此目录里面查找并加载Java类

     

    AppClassLoader:被称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。一版来说,Java应用的类都  是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。

     

    ClassLoader加载类的原理:

               ClassLoader使用的是双亲委托机制来搜索加载类的,每一个ClassLoader实例都有一个父类加载器的引用(不是继承关系,是组合关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它的ClassLoadre实例的父类加载器。当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是有上之下一次检查的。首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没有加载到,则把任务转交给Extension  ClassLoader试图加载,如果没有加载到,则转交给AppClassLoader进行加载,如果它也没有加载到话,则发挥给委托的发起者,有它到指定的文件系统或网络等URL中加载该类,如果都没有加载到此类,那么抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存中,最后返回这个类的内存中Class对象。

    类的加载器双亲委托模型:

                                                                   

     

    2、运行时数据区(内存区)

    是在jvm运行的时候操作所分配的内存区。运行时内存区主要分为5个区域:

                                                                       

    方法区(Methd Area):用于存储类结构信息的地方,包括常量池,静态变量,构造函数。虽然JVM规范把方法区描述为堆的一个逻辑部分,但它却有个别名(non-heap 非堆)

                                                           

    Java堆(Heap):存储java实例或者对象的地方。这块是GC的主要区域。从存储内容上可以看到Java堆和方法区是被java线程共享的。

     

    Java栈(Stack):java栈总是和线程关联在一起,每当创建一个线程时,jvm就会为这个线程创建一个对应的java栈。在这个Java栈中又会包含多个帧栈,每运行一个方法就创建一个帧栈,由于存储局部变量,操作栈,方法返回值等。每一个方法从调用直至执行完成的过程,就对应一个帧栈在Java栈中入栈和出栈的过程。所以java栈是私有。

     

    程序计数器(PC Register):用于保存当前线程执行的内存地址。由于JVN程序是多线程执行的(线程轮转切换),所以为了保证线程切换回来,还能回复到原先状态,就需要一个独立的计数器,记录之前中断的地方,可见程序计数器也是线程私有的。

     

    本地方法栈(Native Method Stack):和Java栈的作用差不多,只不过是为JVM使用到的native方法服务的。

     

    3、执行引擎

    负责执行class文件中包含的字节码指令

    4、本地接口

    主要是调用CC++实现的本地方法及返回结果

     

    JVM内存分配:

    Java虚拟机是一次性分配一块较大的内存空间,然后每次new时都在该空间上进行分配和释放,减少了系统调用的次数,节省了一定的开销,这有点类似于内存池的概念。有了这块空间,如何进行分配和回收就跟GC机制有关系了。

    Java一般内存申请有两种:静态内存和动态内存。很容易理解,编译时就能够确定的内存就是静态内存,即内存是固定的,系统一次性分配。比如int类型变量;动态内存分配就是在程序执行时才知道要分配的存储空间大小,比如java对象的内存空间。综上所述:java栈、程序计数器、本地方法栈都是线程私有的,线程生就生,线程灭就灭,栈中的栈帧随着方法的结束也会撤销,内存自然就跟着回收了。所以几个地方的内存分配和回收是确定的,不需要管。但是java堆和方法区则不一样,我们只有在程序运行期间才知道会创建哪些对象,所以这部分内存分配和回收是动态的。一般说的垃圾回收也是针对这部分的。

     

    垃圾检测和回收算法

             垃圾收集器一般必须完成两件事:检测出垃圾,回收垃圾。检测垃圾一般分为以下几种:

     

    引用计数法:给对象增加一个引用计数器,每当有地方引用这个对象时,就在计数器上加1,引用失效就减1

    可达性分析算法:以根集对象为起始点进行搜索,如果有对象不可达的话,即是垃圾对象。这里的根集一般包括java堆中引用的对象,方法区常量池的引用对象。

     

    总之,jvm在做垃圾回收的时候,会检查堆中的所有对象是否会被这些根集对象引用,不能够被引用的对象就会被垃圾收集器回收。一般回收有一下几种方法:

             1、标记-清除(Mark-sweep):分为两个阶段,标记和清楚。标记所有需要回收的对象,然后统一回收这个是最基础的算法,后续的收集算法 都是基于这个算法扩展的。

             不足:效率低;标记清楚之后会产生大量的碎片。

             2、复制(copying): 此算法把内存空间划分为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前区域,把正在使用中的对象复制到另外区域中。此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去还能进行相应的内存整理,不会出现“内存碎片”问题。当然,此算法的缺点也是很明显,就是需要双倍内存。

             3、标记-整理(Mark-Compact):此算法结合了“标记-清除”和“复制”两个算法的有点。也是两个阶段,第一阶段从根节点开始标记所被引用的对象。第二阶段遍历整个堆,把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“复制”算法的空间问题

             4、分代收集算法:这是当前商业虚拟机常用的垃圾收集算法。分代的垃圾回收策率,是基于这样一个事实:不同的对象的生命周期不一样的。因此,不同生命周期的对象采取不同的收集方式,以便提高回收效率。

            

    为什么要运用分代垃圾回收策率?在java程序运行的过程中,会产生大量的对象,因每个对象所能承担的职责和功能不同,所以也有着不同的生命周期。有的对象生命周期较长,有的对象生命周期较短。试想,在不进行对象存活时间区分的情况下,每次垃圾回收都是对整个堆空间进行回收,那么消耗的时间相对比较长,而对于存活时间较长的对象进行扫描的工作是徒劳的。因此就引入了分治思想,所以分治思想就是因地制宜,将对象进行代划分,把不同的生命周期的对象放在不同的代上使用不同的垃圾回收方法。

     

    如果划分?将对象按其生命周期的不同划分成:年轻代(Young Generation)、老年代(Old Generation)、持久代(Permanent Generation)。其中持久代主要存放的是类信息,所以与java对象的回收关系不大,与回收信息相关的是年轻代,老年代。

     

    年轻代:是所有新对象产生的地方。年轻代被分为3个部分:Ender(出生)区和两个Survivor(幸存者)区(From和To)。当Ender区被对象填满时,就会执行Minor GC。并把所有存活下来的对象转移到其中一个Survivor区(假设为from区)。Minor GC同样会检查存活下来的对象,并把他们转移到另一个Survivor区(假设为to区)。这样在一段时间内总会有一个空的Survivor区。经过多次GC后,仍然存活下来的对象会被转移到老年代内存空间。

     

    年老带:在年轻代经过N次回收的仍然没有被清除的对象会放到老年代,可以说它们是久经沙场而不亡的一代,都是生命周期较长的对象。对于老年代和永久代,就不能再采用年轻代中那样搬移腾挪的回收算法,因为那些对于这些回收战场上的老兵来说是小儿科,通常会在老年代内存被占满时将会触发Full GC,回收整个堆内存。

     

    持久代:用于存放静态文件,比如Java类,方法等。持久代对垃圾回收没有显著的影响。

                                                                             

    我这里之所以最后讲分代,是因为分代里涉及了前面几种算法。年轻代:涉及了复制算法;年老代:涉及了标记-整理(Mark-Sweep的算法。

     

    Java线程池

    java中的ThreadPoolExecutor类

    ThreadPoolExecutor类继承了AbstractExecutorService类,并提供了四个构造器。构造器中分别有一下参数:

    1. corePoolSize:核心池的大小,在创建线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法来预创建线程。即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中。
    2. maximumPoolSize:线程池最大的线程数,表示在线程池中最多能创建多少个线程;
    3. keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize。即当线程池中的线程数大于corePoolSize时,如果一个线程空闲时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,知道线程池中的线程数为0。
    4. unit:参数keepAliveTime的时间单位,有7中取值,在TimeUnit类中有7中静态属性:
      1. TimeUnit.DAYS;               //天
      2. TimeUnit.HOURS;             //小时
      3. TimeUnit.MINUTES;           //分钟
      4. TimeUnit.SECONDS;           //秒
      5. TimeUnit.MILLISECONDS;      //毫秒
      6. TimeUnit.MICROSECONDS;      //微妙
      7. TimeUnit.NANOSECONDS;       //纳秒
    5. workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一版来说阻塞队列有以下几种:
      1. ArrayBlockingQueue
      2. LinkedBlockingQueue
      3. SynchronousQueue

    ArrayBlockingQueue使用较少,一使用LinkedBlokingQueue和SynchronousQueue。线程池排队策率与BlockingQueue有关

    1. threadFactory:线程工厂,主要用来创建线程;
    2. hander:表示当拒绝处理任务时的策率,有一下四种取值:
      1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
      2. ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常
      3. ThreadPoolExecutor.DiscardOlddestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
      4. ThreadPoolExecutor.CallerRunsPolicy:有调用线程处理该任务

     

    ThreadPoolExecutor继承了AbstractExecutorService抽象类,AbstractExecutorService抽象类实现了ExecutorService接口,ExecutorService接口继承了Executor接口。

     

    Executor:是一个顶层接口,在它里面只有一个方法execute(Runnable),返回值为void,参数为Runnable类型,其实就是为了执行传进来的任务;

    然后ExecutorService接口继承了Executor接口,并生命了一些方法:submit、invokeAll、invokeAny以及shutDown等。

    抽象类AbstractExecutorService实现了ExecutorService接口,基本实现了ExecutorService接口中所有的方法;

    然后ThreadPoolExecutor继承了抽象类AbstractExecutorService;

    在ThreadPoolExecutor类中有几个非常重要的方法:

    1. execute():实际上是Executor中声明的方法,在ThreadPoolExecutor进行了具体的实现,这个方法是ThreadPoolExecutor的核心方法,通过这个方法可以向线程池提交一个任务,交线程池去执行。
    2. submit():此方法是在ExecutorService中声明的方法,在AbstractExecutorService就已经有了具体的实现,在ThreadPoolExecutor中并没有对其进行重写,这个方法也是用来向线程池提交任务的,但是它和executor()方法不同,它能够返回任务执行的结果,去看submit()方法的方法实现,会发现它实际上还是调用的execute()方法,只不过它利用了Futrure来获取任务的执行结果
    3. shutDown():是用来关闭线程
    4. shutDownNow():是用来关闭所有线程

     

    深入剖析线程池实现的原理图

    深入解析一下线程池的具体实现原理,将从下面几个方面讲解:

    1. 线程池状态

    在ThreadPoolExecutor中定义了一个volatile变量,另外定义了几个static final变量表示线程池的各个状态:

    volatile in runSize;

    static final int Running = 0;

    static final int shutdown = 1;

    static final int stop = 2;

    static final int terminated=3;

     

    runSize:表示当前线程池状态,它是一个volatile变量用来保证线程之间的可见性

    下面几个static final int 变量表示runSize可能的几个取值

    当创建线程池后,初始时,线程池处于Running状态;

    如果调用了shutdown()方法,则线程池处于shutdown状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;

    如果滴啊用shutdownNow()方法,则线程池处于stop状态,此时线程池不能接受新的任务,并且会尝试终止正在执行的任务;

    当线程池处于shutdown或者stop状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为terminated状态

     

    1. 任务的执行

    ThreadPoolExecutor类中其他的一些比较重要的成员变量:

    private final BlockingQueue<Runnable> workQueue; //任务缓存队列,用来存放等待执行的任务

    private final ReentrantLock mainLock = new ReentrantLock();//线程池的主要状态锁,对线程池状态(比如线程池大小等)的改变都要使用这个锁

    private final HashSet<Worker> workers = new HashSet<Worker>(); //用来存放工作集

    private volatile long  keepAliveTime;    //线程存货时间

    private volatile boolean allowCoreThreadTimeOut;   //是否允许为核心线程设置存活时间

    private volatile int   corePoolSize;   //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)

    private volatile int   maximumPoolSize;   //线程池最大能容忍的线程数

    private volatile int   poolSize;       //线程池中当前的线程数

    private volatile RejectedExecutionHandler handler; //任务拒绝策略

    private volatile ThreadFactory threadFactory;   //线程工厂,用来创建线程

    private int largestPoolSize;   //用来记录线程池中曾经出现过的最大线程数

    private long completedTaskCount;   //用来记录已经执行完毕的任务个数

     

    任务提交给线程池之后处理的策略,主要有一下四点:

    如果当前线程池中线程数目小于corePoolSize,则每来一个线程,就会创建一个线程去执行这个任务;

    如果当前线程池中线程数据大于等于corePoolSize,则没来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一版来说是任务缓存队列已满),则会尝试尝试创建新的线程去执行这个任务;

    如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策率进行处理;

    如果线程池中的线程数量大于corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数据不大于corePoolSize;如果允许核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止

     

    1. 线程池中的线程初始化

    默认情况下,创建线程池之后,线程池中是没有线程的,需要提交任务之后才会创建线程。在实际中如果需要线程池创建之后立即创建线程,可以通过下面两种方法:

    prestartCoreThread():初始化一个核心线程

    prestartAllCoreThread():初始化所有核心线程

     

    1. 任务缓存队列及排队策略

    任务缓存队列,即workQueue,它用来存放等待执行的任务

    workQueue的类型为BlockingQueue<Runnable>,通常可以取下面三种类型:

    ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须制定大小

    LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列的大小,那么默认为Integer.MAX_VALUE

    synchronousQueue:这个队列比较特殊,他不会保存提交的任务,而是将直接新建的一个线程来执行新的任务。

    1. 任务拒绝策略

    当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常通过一下四种策略:

    1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
    2. ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常
    3. ThreadPoolExecutor.DiscardOlddestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
    4. ThreadPoolExecutor.CallerRunsPolicy:有调用线程处理该任务

     

    1. 线程池的关闭

    ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别为shutDown()和shutDownNow(),其中:

    shutDown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会执行新的任务

    shutDownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

    1. 线程池容量的动态调动

    ThreadPoolExecutor提供了动态调用线程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),

    setCorePool():设置核心池大小

    setMaximumPoolSize():设置线程池最大能创建的线程数目大小

    当上述参数从小变大时,ThreadPoolExecutor进行线程赋值,还可能立即创建新的线程来执行任务

    使用示例

    package ThreadPoolExecutor;

     

    public class MyTask implements Runnable {

        private int taskNum;

       

        public MyTask(int num) {

            this.taskNum = num;

        }

     

        @Override

        public void run() {

             System.out.println("正在执行task"+taskNum);

             try {

                Thread.currentThread().sleep(4000);

            } catch (InterruptedException e) {

                // TODO Auto-generated catch block

                e.printStackTrace();

            }

             System.out.println("task" + taskNum + "执行完毕");

        }

     

    }

     

    package ThreadPoolExecutor;

     

    import java.util.concurrent.ArrayBlockingQueue;

    import java.util.concurrent.ThreadPoolExecutor;

    import java.util.concurrent.TimeUnit;

     

    public class Test {

        public static void main(String[] args) {

            ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,

                    new ArrayBlockingQueue<Runnable>(5));

            for(int i = 0 ; i < 15 ; i ++){

                MyTask mytask = new MyTask(i);

                executor.execute(mytask);

                 System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+

                         executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());

            }

            executor.shutdown();

        }

    }

    执行结果:

    正在执行task0

    线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0

    线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0

    正在执行task1

    线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0

    正在执行task2

    线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0

    正在执行task3

    线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0

    正在执行task4

    线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0

    线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0

    线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0

    线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0

    线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0

    线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0

    正在执行task10

    正在执行task11

    线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0

    线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0

    线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:0

    正在执行task13

    正在执行task12

    线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:0

    正在执行task14

    task0执行完毕

    正在执行task5

    task1执行完毕

    正在执行task6

    task2执行完毕

    正在执行task7

    task3执行完毕

    正在执行task8

    task4执行完毕

    正在执行task9

    task11执行完毕

    task10执行完毕

    task13执行完毕

    task14执行完毕

    task12执行完毕

    task5执行完毕

    task6执行完毕

    task9执行完毕

    task8执行完毕

    task7执行完毕

     

    从执行结果可以看出,当线程池中的线程的数目大于5时,便将任务放入缓存队列里面,当任务缓存队列满了之后,便创建新的线程。如果上面程序中,将for循环中改成执行20个任务,就会抛出任务拒绝异常了;

     

    在java doc中,并不建议直接使用ThreadPoolExecutor直接创建线程池,而是使用Executor类中提供的几个静态方法来创建线程池:

    Executor.newCachedThread()://创建一个缓冲池,缓冲池大小为Integer.MAX_VALUE

    Executor.newSingleThreadExecutor()://创建容量为1的缓冲池

    Executor.newFixedThreadPool()://创建固定容量的缓冲池

     

    以下是这个三个静态方法的具体实现:

    public static ExecutorService newFixedThreadPool(int nThreads) {

        return new ThreadPoolExecutor(nThreads, nThreads,

                                      0L, TimeUnit.MILLISECONDS,

                                      new LinkedBlockingQueue<Runnable>());

    }

    public static ExecutorService newSingleThreadExecutor() {

        return new FinalizableDelegatedExecutorService

            (new ThreadPoolExecutor(1, 1,

                                    0L, TimeUnit.MILLISECONDS,

                                    new LinkedBlockingQueue<Runnable>()));

    }

    public static ExecutorService newCachedThreadPool() {

        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

                                      60L, TimeUnit.SECONDS,

                                      new SynchronousQueue<Runnable>());

    }

     

    从它们的具体实现来看,他们实际上也是调用了ThreadPoolExecutor,只不过参数都已经配置好了,

     

    newFixedThreadPool创建的线程池corePoolSize和maximumPoolSize值是相等的,它使用的LinkedBlockingQueue;

    newSingleThreadPool将corePoolSize和maximumPoolSize的值都设置为1,也使用的LinkedBlockingQueue;

    newCachedThreadPool将corePoolSize设置为0,将maximumPoolSize设置为Integer.MAX_VALUE,使用SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程

     

    实际工作中,如果Executors提供的三种静态方法如果能够满足要求,就尽量使用它提供的三个方法,因为自己手动配置ThreadPoolExecutor的参数有点麻烦,要根据实际任务的类型和数据量来进行配置。如果ThreadPoolExecutor达不到要求,可以自己继承ThreadPoolExecutor类进行重写

     

    如何合理配置线程池的大小

    一般需要根据任务的类型来配置线程池大小;

    如果是CPU密集型任务,就需要压榨CPU,参考值可以设为Ncpu+1

    如果是IO密集型任务,参考值可以设为2*Ncpu

    当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。

     

    Java四种线程池

    线程池的优势:

    1. 重用存在的线程,减少对象的创建,消亡的内存开销,性能佳
    2. 可有效控制最大并发线程数,提高系统资源使用率,同时避免过多资源竞争,避免堵塞
    3. 提供定时执行,定期执行,单线程,并发数控制功能。

    Executors提供的四种线程池:

    1. newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需求,可灵活回收空线程,若无可回收的线程,则新建线程

    package ThreadPoolExecutor;

     

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

     

    public class CachedThreadPool {

             public static void main(String[] args) {

                       ExecutorService cachedThreadPool = Executors.newCachedThreadPool();            

                       for(int i = 0 ; i < 10 ; i++ ){

                                final int index = 1;

                                try {

                                         Thread.sleep(index * 1000);

                                } catch (InterruptedException e) {

                                         // TODO Auto-generated catch block

                                         e.printStackTrace();

                                }                          

                                cachedThreadPool.execute(new Runnable(){

                                         @Override

                                         public void run() {

                                                   System.out.println(index);

                                         }                                   

                                });

                       }

                       cachedThreadPool.shutdown();//立即终止线程池

             }

    }

    线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不是每次新增线程

     

    1. newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

    package ThreadPoolExecutor;

     

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

     

    public class FixedThreadPool {

             public static void main(String[] args) {

                       ExecutorService fixedThreadPool  = Executors.newFixedThreadPool(3);

                       for(int i = 0 ; i < 10 ; i ++){

                                final int index = 1;

                                fixedThreadPool.execute(new Runnable(){

                                         @Override

                                         public void run() {

                                                   System.out.println(index);

                                                   try {

                                                            Thread.sleep(2000);

                                                   } catch (InterruptedException e) {

                                                            // TODO Auto-generated catch block

                                                            e.printStackTrace();

                                                   }

                                         }

                                });

                       }       

    fixedThreadPool.shutdown();

             }

    }

    因为线程池大小为3,每个任务输出index后sleep2秒,所以每两秒打印三个数字;

     

    1. newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行

    package ThreadPoolExecutor;

     

    import java.util.concurrent.Executors;

    import java.util.concurrent.ScheduledExecutorService;

    import java.util.concurrent.TimeUnit;

     

    public class ScheduledThreadPool {

             public static void main(String[] args) {

                       ScheduledExecutorService  scheduledThreadPool = Executors.newScheduledThreadPool(5);

                       scheduledThreadPool.schedule(new Runnable(){

                                @Override

                                public void run() {

                                         System.out.println("这是一个延迟线程");

                                }

                               

                       }, 3, TimeUnit.SECONDS);// 表示延迟3秒执行

                      

                       scheduledThreadPool.scheduleAtFixedRate(new Runnable(){

                                @Override

                                public void run() {

                                         System.out.println("delay 1 seconds, and excute every 3 seconds");

                                }

                               

                       }, 1, 2, TimeUnit.SECONDS);// 表示延迟1秒后每3秒执行一次

                      

                       //scheduledThreadPool.shutdown();

             }

    }

     

    1. newSingleThreadPool:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定的顺序(FIFO,LIFO)执行

     

    package ThreadPoolExecutor;

     

    import java.util.concurrent.ExecutorService;

    import java.util.concurrent.Executors;

     

    public class singleThreadExecutor {

      public static void main(String[] args) {

          ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

          for(int i = 0 ; i < 10; i++){

              final int index = 1;

              singleThreadExecutor.execute(new Runnable(){

     

                  @Override

                  public void run() {

                      System.out.println(index);

                      try {

                          Thread.sleep(2000);

                      } catch (InterruptedException e) {

                          // TODO Auto-generated catch block

                          e.printStackTrace();

                      }

                  }

                 

              });

          }

          singleThreadExecutor.shutdown();

      }

    }

    结果依次输出,相当于顺序执行各个任务

     

    线程池的作用:

    线程池是为了限制系统中执行线程的数量

             根据系统环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其它线程排队等候。一个任务执行完毕,再从队列中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

             为什么要用线程池:

    1. 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
    2. 可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,增加服务器的压力(每个线程大约需要1MB的内存,线程开的越多,消耗内存越大,最后导致司机);

    Java里面线程池的顶级接口是Executor,但是严格意义上将Executor并不是一个线程池,而是一个执行线程的工具。真正的线程池接口是ExecutorService.

             比较重要的几个类:

             Executor:真正的线程池接口

             ScheduledExecutorService:能和Timer/TimerTask类似,解决那些需要任务重复执行的问题

             ThreadPoolService:ExecutorService默认实现类

             ScheduledExecutorPoolExecutor:继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。

    要配置一个线程池是复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是最优的,因此在Executors类里面提供了一个静态工厂,生成一些常用的线程池。

     

    1. newSingleThreadExecutor

    创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程在串行执行所有的任务。如果这个唯一的线程因为异常信息中断,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

    1. newFixedThreadPool

    创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程

    1. newCachedThreadPool

    创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么回收空闲(60秒不执行)的线程,当任务增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

    1. newScheduledThreadPool

    创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

     

    一个任务通过execute(Runnable)方法被添加到线程池,任务就是一个Runnable类型的对象,任务的执行方法就是Runnable类型对象的run()方法

    当一个任务通过execute(Runnable)方法欲添加到线程池时:

    如果此时线程池中的数据小于corePoolSize,即使线程池中的线程处于空闲状态,也要创建新的线程来处理被添加的任务。

    如果此时线程池中的数据等于 corePoolSize,但是缓冲队列workQueue未满,那么任务被放入缓冲队列

    如果此时线程池中的数据大于 corePoolSize,缓冲队列workQueue已满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

    如果此时线程池中的数量大于 corePoolSize,缓冲队列workQueue已满,并且线程池中的数量等于maximumPoolSize,那么通过handler所指定的策略来处理此任务。

     

    处理任务的优先级:

    核心线程corePoolSize,任务队列workQueue,最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    展开全文
  • Java 面试只是背答案吗?

    千次阅读 多人点赞 2021-06-09 17:23:55
    3:MySQL 的锁策略有什么? 4:数据库死锁如何解决? 5:事务是什么? 6:事务有什么特性? 7:MySQL 的隔离级别有哪些? 8:MVCC 是什么? 9:谈一谈 InnoDB 10:谈一谈 MyISAM 11:谈一谈 Memory 12:查询执行流程...

    说实话,不背肯定不行的,这些题目务必搞懂!

    由于字数太多,所以只分类给出了面试题目,每道题的答案看文末

    一、32 道 MySQL 面试题

    1:MySQL 的逻辑架构了解吗?

    2:谈一谈 MySQL 的读写锁

    3:MySQL 的锁策略有什么?

    4:数据库死锁如何解决?

    5:事务是什么?

    6:事务有什么特性?

    7:MySQL 的隔离级别有哪些?

    8:MVCC 是什么?

    9:谈一谈 InnoDB

    10:谈一谈 MyISAM

    11:谈一谈 Memory

    12:查询执行流程是什么?

    13:VARCHAR 和 CHAR 的区别?

    14:DATETIME 和 TIMESTAMP 的区别?

    15:数据类型有哪些优化策略?

    16:索引有什么作用?

    17:谈一谈 MySQL 的 B-Tree 索引

    18:了解 Hash 索引吗?

    19:什么是自适应哈希索引?

    20 :什么是空间索引?

    21:什么是全文索引?

    22:什么是聚簇索引?

    23:什么是覆盖索引?

    24:你知道哪些索引使用原则?

    25:索引失效的情况有哪些?

    26:如何定位低效 SQL?

    27:SHOW PROFILE 的作用?

    28:trace 是干什么的?

    29:EXPLAIN 的字段有哪些,具有什么含义?

    30:有哪些优化 SQL 的策略?

    31:MySQL 主从复制的作用?

    32:MySQL 主从复制的步骤?

    二、15 道设计模式面试题

    1:设计模式有哪些原则?

    2:设计模式的分类,你知道哪些设计模式?

    3:说一说简单工厂模式

    4:说一说工厂方法模式

    5:抽象工厂模式了解吗?

    6:单例模式的特点是什么?

    7:单例模式有哪些实现?

    8:讲一讲代理模式

    9:讲一讲装饰器模式

    10:装饰器模式和动态代理的区别?

    11:讲一讲适配器模式

    12:适配器模式和和装饰器模式以及代理模式的区别?

    13:讲一讲策略模式

    14:讲一讲模板模式

    15:讲一讲观察者模式

    三、5 道 Mybatis 面试题

    1:Mybatis 的优缺点?

    2:Mybatis 的 XML 文件有哪些标签属性?

    3:Mybatis 的一级缓存是什么?

    4:Mybatis 的二级缓存是什么?

    5:Mybatis #{} 和 ${} 的区别?

    四、4 道 Spring Data JPA 面试题

    1:ORM 是什么?

    2:JPA 如何使用?

    3:JPA 实体类相关注解有哪些?

    4:对象导航查询是什么?

    五、3 道 Spring MVC 面试题

    1:Spring MVC 的处理流程?

    2:Spring MVC 有哪些组件?

    3:Spring MVC 的相关注解?

    六、4 道 AOP 面试题

    1:AOP 是什么?

    2:AOP 的相关注解有哪些?

    3:AOP 的相关术语有什么?

    4:AOP 的过程?

    七、11 道 Spring IoC 面试题

    1:IoC 是什么?

    2:IoC 容器初始化过程?

    3:依赖注入的实现方法有哪些?

    4:依赖注入的相关注解?

    5:依赖注入的过程?

    6:Bean 的生命周期?

    7:Bean 的作用范围?

    8:如何通过 XML 方式创建 Bean?

    9:如何通过注解创建 Bean?

    10:如何通过注解配置文件?

    11:BeanFactory、FactoryBean 和 ApplicationContext 的区别?

    八、11 道 JUC 面试题

    1:什么是 CAS?

    2:CAS 有什么问题?

    3:有哪些原子类?

    4:AtomicIntger 实现原子更新的原理是什么?

    5:CountDownLatch 是什么?

    6: CyclicBarrier 是什么?

    7:Semaphore 是什么?

    8: Exchanger 是什么?

    9:JDK7 的 ConcurrentHashMap 原理?

    10:JDK8 的 ConcurrentHashMap 原理?

    11:ArrayList 的线程安全集合是什么?

    九、37 道并发面试题

    1:JMM 的作用是什么?

    2:as-if-serial 是什么?

    3:happens-before 是什么?

    4:as-if-serial 和 happens-before 有什么区别?

    5:什么是指令重排序?

    6:原子性、可见性、有序性分别是什么?

    7:谈一谈 volatile

    8:final 可以保证可见性吗?

    9:锁优化有哪些策略?

    10:自旋锁是什么?

    11:什么是自适应自旋?

    12:锁消除是什么?

    13:锁粗化是什么?

    14:偏向锁是什么?

    15:轻量级锁是什么?

    16:偏向锁、轻量级锁和重量级锁的区别?

    17:Lock 和 synchronized 有什么区别?

    18:ReentrantLock 的可重入是怎么实现的?

    19:什么是读写锁?

    20:AQS 了解吗?

    21:AQS 有哪两种模式?

    22:AQS 独占式获取/释放锁的原理?

    23:为什么只有前驱节点是头节点时才能尝试获取同步状态?

    24:AQS 共享式式获取/释放锁的原理?

    25:线程的生命周期有哪些状态?

    26:线程的创建方式有哪些?

    27:线程有哪些方法?

    28:什么是守护线程?

    29:线程通信的方式有哪些?

    30:线程池有什么好处?

    31:线程池处理任务的流程?

    32:有哪些创建线程池的方法?

    33:创建线程池有哪些参数?

    34:如何关闭线程池?

    35:线程池的选择策略有什么?

    36:阻塞队列有哪些选择?

    37:谈一谈 ThreadLocal

    十、32 道 JVM 面试题

    1:运行时数据区是什么?

    2:程序计数器是什么?

    3:Java 虚拟机栈的作用?

    4:本地方法栈的作用?

    5:堆的作用是什么?

    6:方法区的作用是什么?

    7:运行时常量池的作用是什么?

    8:直接内存是什么?

    9:内存溢出和内存泄漏的区别?

    10:堆溢出的原因?

    11:栈溢出的原因?

    12:运行时常量池溢出的原因?

    13:方法区溢出的原因?

    14:创建对象的过程是什么?

    15:对象分配内存的方式有哪些?

    16:对象分配内存是否线程安全?

    17:对象的内存布局了解吗?

    18:对象的访问方式有哪些?

    19:如何判断对象是否是垃圾?

    20:Java 的引用有哪些类型?

    21:有哪些 GC 算法?

    22:你知道哪些垃圾收集器?

    23:ZGC 了解吗?

    24:你知道哪些内存分配与回收策略?

    25:你知道哪些故障处理工具?

    26:Java 程序是怎样运行的?

    27:类加载是什么?

    28:类初始化的情况有哪些?

    29:类加载的过程是什么?

    30:有哪些类加载器?

    31:双亲委派模型是什么?

    32:如何判断两个类是否相等?

    十一、6 道 IO 流面试题

    1:同步/异步/阻塞/非阻塞 IO 的区别?

    2:什么是 BIO?

    3:什么是 NIO?

    4:什么是 AIO?

    5:java.io 包下有哪些流?

    6:序列化和反序列化是什么?

    十二、7 道集合面试题

    1:说一说 ArrayList

    2:说一说 LinkedList

    3:Set 有什么特点,有哪些实现?

    4:TreeMap 有什么特点?

    5:HashMap 有什么特点?

    6:HashMap 相关方法的源码?

    7:HashMap 为什么线程不安全?

    十三、10 道面向对象面试题

    1:谈一谈你对面向对象的理解

    2:面向对象的三大特性?

    3:重载和重写的区别?

    4:类之间有哪些关系?

    5:Object 类有哪些方法?

    6:内部类的作用是什么,有哪些分类?

    7:访问权限控制符有哪些?

    8:接口和抽象类的异同?

    9:接口和抽象类应该怎么选择?

    10:子类初始化的顺序

    十四、12 道语言特性面试题

    1:Java 语言的优点?

    2:Java 如何实现平台无关?

    3:JDK 和 JRE 的区别?

    4:Java 按值调用还是引用调用?

    5:浅拷贝和深拷贝的区别?

    6:什么是反射?

    7:Class 类的作用?如何获取一个 Class 对象?

    8:什么是注解?什么是元注解?

    9:什么是泛型,有什么作用?

    10:泛型擦除是什么?

    11:JDK8 新特性有哪些?

    12:异常有哪些分类?


    为了方便各位小伙伴能够复习自己不懂的面试题,吴师兄把这些面试题的答案整理成了 PDF,免费送给大家,只求大家能够一键三连,给大家看一下目录,保证方便复习。

    在这里插入图片描述

    无论是为了复习,还是为了面试,这份面试题肯定可以助你一臂之力,大家可以在吴师兄的公众号「五分钟学算法」后台回复「Java面试题」,就可以免费获取这份面试题的 PDF 版本。

    另外,大家想看在线版的,也可以到吴师兄的个人网站来看,已经有十几万的小伙伴登录学习了,点击查看Java面试题

    作者简介

    作者:大家好,我是程序员吴师兄,在 GitHub 上开源了一个项目 LeetCodeAnimation,目前有 60k star,通过动画的形式讲解算法,已经帮助成千上万的程序员入门算法了,欢迎关注公众号「五分钟学算法」,和我们一起学习算法。
    转载说明:未获得授权,禁止转载

    展开全文
  • 计算机等级考试--二级Java的知识点大全

    万次阅读 多人点赞 2019-03-16 20:42:59
    1)确定性,算法中每一步骤必须有明确定义,不允许有多义性; 2)有穷性,算法必须能在有限的时间内完,即能在执行有限个步骤后终止; 3)可行性,算法原则上能够精确地执行; 4)拥有足够的情报。 3、算法...

    第一章  数据结构与算法

    【考点1】算法的基本概念

    1、算法:是指一组有穷的指令集,是解题方案的准确而完整的描述。算法不等于程序,也不等于计算方法。

    2、算法的基本特征:

    1)确定性,算法中每一步骤都必须有明确定义,不允许有多义性;

    2)有穷性,算法必须能在有限的时间内做完,即能在执行有限个步骤后终止;

    3)可行性,算法原则上能够精确地执行;

    4)拥有足够的情报。

    3、算法的组成要素:一个算法由数据对象的运算和操作以及其控制结构这两部分组成。

    4、算法的基本运算和操作:算术运算,逻辑运算,关系运算,数据传输。

    5、算法的基本控制结构:顺序,选择,循环。

    6、算法基本设计方法:列举法、归纳法、递推、递归、减半递推技术。

    【考点2】算法的复杂度

    1、算法效率的度量——算法的复杂度:时间复杂度和空间复杂度。

    1)算法时间复杂度:指执行算法所需要的计算工作量。通常,一个算法所用的时间包括编译时间和运行时间。

    2)算法空间复杂度:指执行这个算法所需要的内存空间。包括算法程序所占的空间,输入的初始数据所占的空间,算法执行过程中所需的额外空间。

    空间复杂度和时间复杂度并不相关。

    【考点3】数据结构的基本概念

    数据:数据是客观事物的符号表示,是能输入到计算机中并被计算程序识别和处理的符号的总称,如文档,声音,视频等。

    数据元素:数据元素是数据的基本单位。

    数据对象:数据对象是性质相同的数据元素的集合。

    数据结构:是指由某一数据对象中所有数据成员之间的关系组成的集合。

    【考点4】逻辑结构和存储结构

    1、数据结构可分为数据的逻辑结构和存储结构。

    1)数据的逻辑结构是对数据元素之间的逻辑关系的描述,与数据的存储无关,是面向问题的,是独立于计算机的。它包括数据对象和数据对象之间的关系。

    2)数据的存储结构也称为数据的物理结构,是数据在计算机中的存放的方式,是面向计算机的,它包括数据元素的存储方式和关系的存储方式。

    2、存储结构和逻辑结构的关系:一种数据的逻辑结构可以表示成多种存储结构即数据的逻辑结构和存储结构不一定一一对应。

    3、常见的存储结构有:顺序,链接,索引等。采用不同的存储结构其数据处理的效率是不同的。

    【考点5】线性结构和非线性结构

    1、线性结构的条件(一个非空数据结构):(1)有且只有一个根结点;(2)每一个结点最多有一个前件,也最多有一个后件。

    2、非线性结构:不满足线性结构条件的数据结构。

    栈、队列、双向链表是线性结构,树、二叉树为非线性结构。

    【考点6】线性表及其顺序存储结构

    1、线性表是由一组数据元素构成,数据元素的位置只取决于自己的序号,元素之间的相对位置是线性的。

    2、在复杂线性表中,由若干项数据元素组成的数据元素称为记录;由多个记录构成的线性表称为文件。

    3、非空线性表的结构特征:

    (1)有且只有一个根结点a1,它无前件;

    (2)有且只有一个终端结点an,它无后件;

    (3)除根结点与终端结点外,其他所有结点有且只有一个前件,也有且只有一个后件。

    结点个数n称为线性表的长度,当n=0时,称为空表。

    4、线性表的顺序存储结构具有以下两个基本特点:

    (1)线性表中所有元素所占的存储空间是连续的;

    (2)线性表中各数据元素在存储空间中是按逻辑顺序依次存放的。

    元素ai的存储地址为:ADR(ai)=ADR(a1)+(i-1)*k,ADR(a1)为第一个元素的地址,k代表每个元素占的字节数。

    5、顺序表的运算:查找、插入、删除。

    【考点7】线性链表

    线性链表是线性表的链式存储结构,数据结构中的每一个结点对应于一个存储单元,这种存储单元称为存储结点,简称结点。结点由两部分组成:(1) 用于存储数据元素值,称为数据域;(2) 用于存放指针,称为指针域,用于指向前一个或后一个结点。

    在链式存储结构中,存储数据结构的存储空间可以不连续,各数据结点的存储顺序与数据元素之间的逻辑关系可以不一致,而数据元素之间的逻辑关系是由指针域来确定的。

    链式存储方式既可用于表示线性结构,也可用于表示非线性结构。

    线性单链表中,HEAD称为头指针,HEAD=NULL(或0)称为空表。

    双向链表有两个指针:左指针(Llink)指向前件结点,右指针(Rlink)指向后件结点。

    循环链表:循环链表与单链表的不同的是它的最后一个结点的指针域存放的事指向第一个结点的指针而单链表存放的是空指针。

     

    线性链表的基本运算:查找、插入、删除。

    【考点8】栈

    1、栈的基本概念

    栈是一种特殊的线性表,只允许在表的一端进行插入和删除的线性表;插入,删除的一端为栈顶,另一端为栈底;当表中没有元素时为空栈。

    栈是一种后进先出(或先进后出Last In First Out)的线性表。栈具有记忆功能。栈的实例:火车调度,子弹夹。

    2、栈的存储结构

    顺序存储结构:用一组地址连续的存储单元即一维数组来存储;

    链式存储:用线性链表来存储;

    3、栈的基本运算

    (1) 入栈运算,在栈顶位置插入元素;

    (2) 退栈运算,删除元素(取出栈顶元素并赋给一个指定的变量);

    (3) 读栈顶元素,将栈顶元素赋给一个指定的变量,此时指针无变化。

    【考点9】队列

    1.队列的基本概念

    队列是一种特殊的线性表,只允许在表的一端插入,在另一端删除,允许插入的一端是队尾(rear),允许删除的一端为队头(front);当表中没有元素是空队列;队列是一种先进先出的线性表。(FIFO)

    2、队列的存储结构

    顺序存储:一维数组。

    链式存储:线性链表。

    3、队列的运算:

    (1) 入队运算:从队尾插入一个元素;  (2) 退队运算:从队头删除一个元素。

    4、队列的顺序存储结构一般采用循环队列的形式。循环队列s=0表示队列为空;s=1且front=rear表示队满。

    5、计算循环队列的元素个数:“尾指针减头指针”,若为负数,再加其容量即可。

    【考点10】树的基本概念

    树是一种非线性结构,是n个结点的有限集。当n=0 时为空树,n>0时为非空树。结点的度:结点所拥有的子树的个数。

    叶子结点:度为0的结点。

    分支结点:除叶子结点以外的结点。

    结点的层次:根结点在第一层,同一层上左右结点的子结点在下一层。

    树的深度:所处层次最大的那个结点的层次。

    树的度:树中所有结点的度的最大值。

    【考点11】二叉树及其基本性质

    1、二叉树的概念

    二叉树是一种特殊的树形结构,每个结点最多只有两棵子树,且有左右之分不能互换,因此,二叉树有五种不同的形态。

    2、二叉树的性质

    性质1 在二叉树的第k层上,最多有2k-1(k≥1)个结点。

    性质2 深度为m的二叉树最多有2m-1个结点。

    性质3 在任意一棵二叉树中,度为0的结点(叶子结点)总是比度为2的结点多一个。

    性质4 具有n个结点的二叉树,其深度不小于[log2n]+1,其中[log2n]表示为log2n的整数部分。

    【考点12】满二叉树与完全二叉树

    满二叉树:除最后一层外,每一层上的所有结点都有两个子结点。在满二叉树中,每一层上的结点数都达到最大值,即在满二叉树的第k层上有2k-1个结点,且深度为m的满二叉树有2m-1个结点。

    完全二叉树是指这样的二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。

    满二叉树是完全二叉树,而完全二叉树一般不是满二叉树。

    【考点13】完全二叉树的性质

    性质1 具有n个结点的完全二叉树的深度为[log2n]+1。

    性质2 完全二叉树中度为1的结点数为0或1。

    【考点14 】二叉树的遍历

    1、前序遍历:先访问根结点、然后遍历左子树,最后遍历右子树;并且,在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树。

    前序遍历图5可得:ABCDFHEG。

    2、中序遍历:先遍历左子树、然后访问根结点,最后遍历右子树;并且,在遍历左、右子树时,仍然先遍历左子树,然后访问根结点,最后遍历右子树。

    中序遍历图5可得:BAFHDCGE。

    3、后序遍历:先遍历左子树、然后遍历右子树,最后访问根结点;并且,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后访问根结点。

    后序遍历图5可得:BHFDGECA。

    【考点15】顺序查找

    顺序查找是从表的一端开始,依次扫描表中的各个元素,并与所要查找的数进行比较。

    在下列两种情况下也只能采用顺序查找:

    (1)如果线性表为无序表,则不管是顺序存储结构还是链式存储结构,只能用顺序查找。

    (2)即使是有序线性表,如果采用链式存储结构,也只能用顺序查找。

    【考点16】二分查找

    二分查找的条件:(1)用顺序存储结构   (2)线性表是有序表。

    对于长度为n的有序线性表,在最坏情况下,二分法查找只需比较log2n次,而顺序查找需要比较n次。

    【考点17】排序

    1、交换排序

    (1)冒泡排序法,在最坏的情况下,冒泡排序需要比较次数为n(n-1)/2。

    (2)快速排序法 ,在最坏的情况下,快速排序需要比较次数为n(n-1)/2。

    2、插入类排序法:

    (1)简单插入排序法,最坏情况需要n(n-1)/2次比较;

    (2)希尔排序法,最坏情况需要O(n1.5)次比较。(大写O是算法复杂度的表示方法)

    3、选择类排序法:

    (1)简单选择排序法,最坏情况需要n(n-1)/2次比较;

    (2)堆排序法,最坏情况需要O(nlog2n)次比较。

    相比以上几种(除希尔排序法外),堆排序法的时间复杂度最小。

    第二章  程序设计基础

    【考点1】程序设计方法与风格

    形成良好的程序设计风格需注意:

    1、源程序文档化; 2、数据说明的方法; 3、语句的结构;  4、输入和输出。

    【考点2】结构化程序设计方法的四条原则

    1、自顶向下; 2、逐步求精; 3、模块化; 4、限制使用goto语句。

    【考点3】结构化程序的基本结构

    顺序结构:是最基本、最普通的结构形式,按照程序中的语句行的先后顺序逐条执行。

    选择结构:又称为分支结构,它包括简单选择和多分支选择结构。

    循环结构:根据给定的条件,判断是否要重复执行某一相同的或类似的程序段。循环结构对应两类循环语句:先判断后执行的循环体称为当型循环结构;先执行循环体后判断的称为直到型循环结构。

    【考点4】面向对象的程序设计及面向对象方法的优点

    面向对象的程序设计以对象为核心,强调对象的抽象性,封装性,继承性和多态性。

    面向对象方法的优点

    (1)人类习惯的思维方法一致; (2)稳定性好; (3)可重用性好;

    (4)易于开发大型软件产品;   (5)可维护性好。

    【考点5】对象及其特点

    对象(object):面向对象方法中最基本的概念,可以用来表示客观世界中的任何实体,对象是实体的抽象。

    对象的基本特点:

    (1)标识惟一性; (2)分类性; (3)多态性; (4)封装性; (5)模块独立性好。

    【考点6】属性,类和实例

    属性:即对象所包含的信息,它在设计对象时确定,一般只能通过执行对象的操作来改变。

    类:是具有相似属性与操作的一组对象。类是关于对象性质的描述。类是对象的抽象,对象是其对应类的一个实例。

    【考点7】消息及其组成

    消息:是一个实例与另一个实例之间传递的信息。对象间的通信靠消息传递。它请求对象执行某一处理或回答某一要求的信息,它统一了数据流和控制流。

    消息的组成包括:

    (1)接收消息的对象的名称; (2)消息标识符,也称消息名; (3)零个或多个参数。

    【考点8】继承和多态

    1、继承:是使用已有的类定义作为基础建立新类的定义技术,广义指能够直接获得已有的性质和特征,而不必重复定义他们。

    2、继承具有传递性,一个类实际上继承了它上层的全部基类的特性。

    3、继承分单继承和多重继承。单继承指一个类只允许有一个父类,即类等级为树形结构;多重继承指一个类允许有多个父类。

    4、多态性:是指同样的消息被不同的对象接受时可导致完全不同的行动的现象。

    第三章  软件工程基础

    【考点1】软件定义与软件特点

    软件指的是计算机系统中与硬件相互依存的另一部分,包括程序、数据和相关文档的完整集合。

    名称

    描述

    程序

    软件开发人员根据用户需求开发的、用程序设计语言描述的、适合计算机执行的指令序列

    数据

    使程序能正常操纵信息的数据结构

    文档

    与程序的开发、维护和使用有关的图文资料

    1、软件的特点:

    1)软件是一种逻辑实体,具有抽象性;

    2)软件的生产与硬件不同,它没有明显的制作过程;

    3)软件在运行、使用期间不存在磨损、老化问题;

    4)软件的开发、运行对计算机系统具有依赖性,受计算机系统的限制,这导致了软件移植的问题;

    5)软件复杂性高,成本昂贵;

    6)软件开发涉及诸多的社会因素。

    2、根据应用目标的不同,软件可分应用软件、系统软件和支撑软件(或工具软件)。

    名称

    描述

    应用软件

    为解决特定领域的应用而开发的软件,如办公自动化软件

    系统软件

    计算机管理自身资源,提高计算机使用效率并为计算机用户提供各种服务的软件,如操作系统

    支撑软件(或工具软件)

    支撑软件是介于两者之间,协助用户开发软件的工具性软件。

    【考点2】软件的生命周期

    软件生命周期是指软件产品从提出、实现、使用维护到停止使用退役的整个过程。可分为软件定义,软件开发及软件维护3个阶段。软件生命周期中,能够准确确定软件系统必须做什么和必须具备哪些功能的阶段是:需求分析。

    【考点3】软件危机和软件工程的概念

    软件危机泛指在计算机软件的开发和维护过程中遇到的一系列严重的问题,集中表现在成本,质量。生产效率等几个方面。

    所谓软件工程是指采用工程的概念、原理、技术和方法指导软件的开发与维护。是建立并使用完善的工程化原则,以较经济的手段获得,能在实际机器上有效运行的可靠软件的一系列方法;软件工程的主要思想强调在软件开发过程中需要应用工程化原则。软件工程的核心思想是把软件当作一个工程产品来处理。

    软件工程包括3个要素:方法,工具和过程

    名称

    描述

    方法

    方法是完成软件工程项目的技术手段

    工具

    工具支持软件的开发、管理、文档生成

    过程

    过程支持软件开发的各个环节的控制、管理

    【考点4】软件工程过程

    软件工程过程是把软件转化为输出的一组彼此相关的资源活动,包含4种基本活动:

    (1)P(plan)——软件规格说明;   (2)D(do)——软件开发;

    (3)C(check)——软件确认;      (4)A(action)——软件演进。

    【考点5】软件开发技术和软件工程管理

    1、软件工程的理论和技术性研究的内容主要包括软件开发技术和软件工程管理。

    2、软件开发技术包括软件开发方法学、开发过程、开发工具和软件工程环境,其主体内容是软件开发方法学。

    3、软件开发方法包括分析方法,设计方法和程序设计方法。

    4、软件工程管理包括软件管理学,软件工程经济学,软件心理学等。

    5、软件管理学包括人员组织,进度安排,质量保证,配置管理,项目计划等。

    6、软件工程经济学是研究软件开发中成本的估算,成本效益的方法和技术。

    【考点6】软件工程的原则

    软件工程的原则:抽象,信息隐蔽,模块化,局部化,确定性,一致性,完备性,可验证性。

    【考点7】需求分析概述

    需求分析阶段的工作:需求获取,需求分析,编写需求规格说明书,需求评审。

    需求分析方法有:

    (1)结构化需求分析方法;

    ①面向数据结构的Jackson方法(ISD);

    ②面向数据流的结构化分析方法(SA);

    ③面向数据结构的结构化数据系统开发方法(DSSD);

    (2)面向对象的分析的方法(OOA)。

    从需求分析建立的模型的特性来分:静态分析和动态分析。

    【考点8】结构化方法和结构化分析方法

    1、结构化方法包括结构化分析方法,结构化设计方法,结构化编程方法。

    结构化方法中,软件功能分解属于总体设计阶段。

    2、结构化分析方法的概念

    结构化分析方法是面向数据流自顶而下逐步求精进行需求分析的方法。

    结构化分析方法在软件需求分析阶段的应用。

    3、结构化分析的常用工具

    (1)数据流图(DFD-Data Flow Diagram):是结构化分析方法中用于系统逻辑模型的一种工具。它以图形的方式描绘在系统中流动和处理的过程。

    数据流图中四种基本的符号。

    1)箭头:表示数据流,数据流是数据在系统中传播的路径。

    2)圆或椭圆:表示加工,加工又称为数据处理,是对数据流进行某些操作或变换。

    3)双横:表示数据存储(数据源)。数据存储又称为文件,指暂时保存的数据,它可以是数据库文件或任何形式的数据组织。

    4)方框:数据的源点或终点。它是软件系统外部环境中的实体,统称外部实体

    (2)数据字典(DD):它是结构分析方法的核心,是用来描述系统中所用到的全部数据和文件的文档,作用是对DFD中出现的被命名的图形元素进行确切解释。

        数据字典由以下4类元素组成

    1)数据流  2)数据流分量 3)数据存储 4)处理

    (3)判定树(决策树):是一种描述加工的图形工具,适合描述时候处理中具有多个判断,而且每个决策与若干条件有关。

    (4)判定表:与判定树类似,也是一种描述加工的图形工具。如果一个加工逻辑有多个条件、多个操作,并且在不同的条件组合下执行不同的操作,那么可以使用判定表来描述。

    【考点9】软件需求规格说明书

    软件需求规格说明书(SRS,Software Requirement Specification)是需求分析阶段得出的最主要的文档。软件需求规格说明书的特点:有正确性、无歧义性、完整性、可验证性、一致性、可理解性、可修改性和可追踪性。其中最重要的是无歧义性。

    【考点10】软件设计的基本概念

    软件设计是确定系统的物理模型。

    软件设计是开发阶段最重要的步骤,是将需求准确地转化为完整的软件产品或系统的唯一途径。

    从技术观点上看,软件设计包括软件结构设计、数据设计、接口设计、过程设计。

    (1)结构设计定义软件系统各主要部件之间的关系;

    (2)数据设计将分析时创建的模型转化为数据结构的定义;

    (3)接口设计是描述软件内部、软件和协作系统之间以及软件与人之间如何通信;

    (4)过程设计则是把系统结构部件转换为软件的过程性描述。

    从工程管理角度来看,软件设计分两步完成:概要设计和详细设计。

    (1)概要设计将软件需求转化为软件体系结构、确定系统级接口、全局数据结构或数据库模式;

    (2)详细设计确立每个模块的实现算法和局部数据结构,用适当方法表示算法和数据结构的细节。

    【考点11】软件设计的基本原理

    1、软件设计中应该遵循的基本原理和与软件设计有关的概念:

    模块化:把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能。

    抽象化:抽出事物的本质特性而暂时不考虑它们的细节。

    信息隐藏和局部化:信息隐蔽是指在一个模块内包含的信息(过程或数据),对于不需要这些信息的其他模块来说是不能访问的,实现信息隐蔽依靠对象的封装。

    模块独立性:模块独立性是指每个模块只完成系统要求的独立的子功能,并且与其他模块的联系最少且接口简单。模块的独立程度是评价设计好坏的重要度量标准。

    【考点12】耦合性和内聚性

    衡量软件的模块独立性是用耦合性和内聚性两个定性的度量标准。

    耦合性:是对一个软件结构内不同模块之间互联程度的度量。耦合性的强弱取决于模块间接口的复杂程度。

    内聚性:是一个模块内部各个元素间彼此结合的紧密程度的度量。

    一个模块的内聚性越强则该模块的模块独立性越强。一个模块与其他模块的耦合性越强则该模块的模块独立性越弱。

    在结构程序设计中,模块划分的原则是模块内具有高内聚度,模块间具有低耦合度。

    耦合和内聚的种类。

    耦合度由低到高:非直接耦合,数据耦合,标记耦合,控制耦合,外部耦合,公共耦合,内容耦合。

    内聚性由强到弱:功能内聚,顺序内聚,通信内聚,过程内聚,时间内聚,逻辑内聚,偶然内聚。

    【考点13】结构化设计方法

    结构化分析方法是面向数据流自顶而下,逐步求精进行需求分析的方法,基本思想将软件设计成由相对独立,单一功能的模块组成的结构,与结构分析方法衔接使用,以数据流图为基础得到软件的模块结构,适用于变换型结构和事物型结构的目标系统。

    1、概要设计的任务:(1)划分出组成系统的物理元素  (2)设计软件的结构

    2、概要设计的工具:

    结构图(SC-Structure Chart)也称程序结构图,在结构图中,模块用一个矩形表示,箭头表示模块间的调用关系。可以用带注释的箭头表示模块调用过程中来回传递的信息。还可用带实心圆的箭头表示传递的是控制信息,空心圆箭心表示传递的是数据。

    结构图的基本形式:基本形式、顺序形式、重复形式、选择形式。

    结构图有四种模块类型:传入模块、传出模块、变换模块和协调模块。

    程序结构图中的专业术语:

    名称

    描述

    深度

    表示控制的层数

    上级模块,从属模块

    上,下两层模块a和b,且有a调用b,则a是上级模块,b是从属模块

    宽度

    整体控制跨度(最大模块的层)的表示

    扇入

    调用该模块的模块个数

    扇出

    一个模块直接调用的其他模块数

    原子模块

    树中位于叶子节点的模块

    3、面向数据流的设计方法

    任何软件系统都可以用数据流图表示,典型的数据流类型有两种:变换型和事务型。

    变换型系统结构图由输入、中心变换、输出三部分组成。

    4、设计的准则

    (1)提高模块独立性。

    (2)模块规模适中。

    (3)深度,宽度,扇出和扇入适当。如果深度过大,则说明有的控制模块可能简单了,如果宽度过大,则说明系统的控制过于集中,扇出过大说明模块过分复杂,需要控制和协调过多的下级模块,应适当加中间层次,扇出过小可以把模块进一步分解成若干小模块,或合并到上级模块中,扇入越大则共享该模块的上级数目越多。好的软件设计结构通常顶层高扇出,中间扇出较少,底层高扇入。

    (4)使模块的作用域在该模块的控制域内。

    (5)减少模块的接口和界面的复杂性。

    (6)设计成单入口,单出口的模块。

    (7)设计功能可预测的模块。

    详细设计常用的设计工具(工程设计工具):图形工具,表格工具和语言工具。

    图形工具:

    程序流程图:箭头表示控制流,方框表示加工步骤,菱形表示逻辑条件。

    N-S图:有五种基本图形。

    PAD图:问题分析图,有五种基本图型。

    表格工具:判定表。

    语言工具:PDL——过程设计语言(结构化的英语和伪码)。

    【考点14】软件测试的目标和准则

    软件测试的目标:发现程序中的错误。

    软件测试的准则:

    (1)所有测试都是应追溯到需求。

    (2)严格执行测试计划,排除测试的随意性。

    (3)充分注意测试中的群集表现。程序中存在错误的概率与该程序中已发现的错误数成正比。

    (4)程序员应避免检查自己的程序。

    (5)穷举测试不可能。穷举测试是把程序所有可能的执行路径都进行检查,即使小规模的程序的执行路径数也相当大,不可能穷尽,说明测试只能证明程序有错,不能证明程序中无错。

    (6)妥善保存测试计划,测试用例出错统计和最终分析报告。

    【考点15】软件测试方法

    从是否需要执行被测软件的角度分为静态测试和动态测试;按功能分为白盒测试和黑盒测试

    1、静态测试和动态测试

    静态测试包括代码检查、静态结构分析、代码质量度量。不实际运行软件,主要通过人工进行。

    动态测试是通过运行软件来检验软件中的动态行为和运行结果的正确性。动态测试的关键是使用设计高效、合理的测试用例。测试用例就是为测试设计的数据,由测试输入数据(输入值集)和预期的输出结果(输出值集)两部份组成。测试用例的设计方法一般分为两类:黑盒测试方法和白盒测试方法。

    2、白盒测试和黑盒测试

    (1)白盒测试

    白盒测试也称为结构测试或逻辑测试,是把程序看成装在一只透明的白盒子里,测试者完全了解程序的结构和处理过程。它根据程序的内部逻辑来设计测试用例,检查程序中的逻辑通路是否都按预定的要求正确地工作。

    白盒测试的基本原则:

    (1)保证所测模块中每一独立路径至少执行一次。

    (2)保证所测模块所有判断的每一分支至少执行一次。

    (3)保证所测模块每一循环都在边界条件和一般条件下至少各执行一次。

    (4)验证所有内部数据结构的有效性。

    (5)按照白盒测试的基本原则,“白盒”法是穷举路径测试。

    白盒测试的方法:逻辑覆盖,基本路经测试。

    (2)黑盒测试

    黑盒测试也称功能测试或数据驱动测试,是把程序看成一只黑盒子,测试者完全不了解,或不考虑程序的结构和处理过程。它根据规格说明书的功能来设计测试用例,检查程序的功能是否符合规格说明的要求。

    黑盒测试的方法:等价划分法,边界值分析法,错误推测法。

    【考点16】软件测试的实施

    软件测试过程分4个步骤,即单元测试、集成测试、验收测试和系统测试。

    单元测试是对软件设计的最小单位——模块进行正确性检验的测试,单元测试的根据是源程序和详细设计说明书,单元测试的技术可以采用静态分析和动态测试。

    单元测试期间对模块进行的测试:模块接口,局部数据结构,重要的执行通路,出错处理通路,边界条件。

    驱动模块相当于被测模块的主程序,它接收测试数据,并传给所测模块,输出实际测试结果

    桩模块通常用于代替被测模块调用的其他模块,其作用仅做少量的数据操作,是一个模拟子程序。

    集成测试是测试和组装软件的系统化技术,主要目的是发现与接口有关的错误,集成测试的依据是概要设计说明书。

    集成测试的方法:非增量方式组装和增量方法组装。

    增量方式包括自顶而下的增量方式,自底而上的增量方式和混合增量方式。

    确认测试的任务是验证软件的功能和性能,确认测试的实施首先运用黑盒测试方法,对软件进行有效性测试,即验证被测软件是否满足需求规格说明确认的标准。

    检查软件产品是否符合需求定义的过程是:确认测试。

    系统测试是通过测试确认的软件,作为整个基于计算机系统的一个元素,与计算机硬件、外设、支撑软件、数据和人员等其他系统元素组合在一起,在实际运行(使用)环境下对计算机系统进行一系列的集成测试和确认测试。

    系统测试的具体实施一般包括:功能测试、性能测试、操作测试、配置测试、外部接口测试、安全性测试等。

    【考点17】程序调试

    在对程序进行了成功的测试之后将进入程序调试(通常称Debug,即排错)。

    程序的调试任务是诊断和改正程序中的错误。

    程序调试和软件测试的区别:

    (1)软件测试是尽可能多地发现软件中的错误,而程序调试先要发现软件的错误,然后借助于一定的调试工具去执行找出软件错误的具体位置。

    (2)软件测试贯穿整个软件生命期,调试主要在开发阶段。

    程序调试的基本步骤:

    (1)错误定位。从错误的外部表现形式入手,研究有关部分的程序,确定程序中出错位置,找出错误的内在原因;

    (2)修改设计和代码,以排除错误;

    (3)进行回归测试,防止引进新的错误。

    软件调试可分为静态调试和动态调试。静态调试主要是指通过人的思维来分析源程序代码和排错,是主要的设计手段,而动态调试是辅助静态调试的。

    主要的调试方法有:

    (1)强行排错法; (2)回溯法; (3)原因排除法,包括演绎法,归纳法和二分法。

    第四章  数据库设计基础

    【考点1】数据库的基本概念

    数据(Data)是数据库存储的基本对象,是描述事物的符号记录。

    数据库(DB)是长期储存在计算机内、有组织的、可共享的大量数据的集合,它具有统一的结构形式并存放于统一的存储介质内,是多种应用数据的集成,并可被各个应用程序所共享,所以数据库技术的根本目标是解决数据共享问题。

    数据库管理系统(DBMS)是数据库的管理机构,负责数据库中的数据组织、数据操纵、数据维护、控制及保护和数据服务等。数据库管理系统是数据库系统的核心。数据库系统包含数据库和数据库管理系统。

    数据库管理系统的功能:

    (1)数据模式定义:即为数据库构建其数据框架;

    (2)数据存取的物理构建:为数据模式的物理存取与构建提供有效的存取方法与手段;

    (3)数据操纵:为用户使用数据库的数据提供方便,如查询、插入、修改、删除等以及简单的算术运算及统计;

    (4)数据的完整性、安全性定义与检查;

    (5)数据库的并发控制与故障恢复;

    (6)数据的服务:如拷贝、转存、重组、性能监测、分析等。

    为完成数据库管理系统的功能,数据库管理系统提供相应的数据语言:

    数据定义语言(DDL):负责数据模式定义和数据物理存取构建。

    数据操纵语言(DML):负责数据的操纵。

    数据控制语言(DCL):负责数据完整性,安全性的定义与检查以及并发控制,故障恢复等功能。

    数据语言按使用方式具有两个结构形式:交互式命令语言(自含型和自主型语言)和宿主型语言。

    数据库管理员(DBA)的工作:数据库设计,数据库维护,改善系统性能,提高系统效率。

    数据库系统(DBS)是指在计算机系统中引入数据库后的系统,一般由数据库、数据库管理系统、应用系统、数据库管理员和用户构成。

    数据库应用系统(DBAS)是数据库系统再加上应用软件及应用界面这三者所组成,具体包括:数据库、数据库管理系统、数据库管理员、硬件平台、软件平台、应用软件、应用界面。

    【考点2】数据管理的发展和基本特点

    数据管理技术的发展经历了三个阶段:人工管理阶段、文件系统阶段和数据库系统阶段,数据独立性最高的阶段是数据库系统阶段。

    人工管理阶段特点:(1)计算机系统不提供对用户数据的管理功能(2)数据不能共享(3)不单独保存数据。

    文件系统阶段的缺陷:(1)数据冗余(2)不一致性(3)数据联系弱。

    数据库系统的发展阶段:第一代的网状、层次数据库系统;第二代的关系数据库系统;第三代的以面向对象模型为主要特征的数据库系统。

    数据库系统的基本特点:

    (1)数据的高集成性 (2)数据的高共享性和低冗余性 (3)数据高独立性 (4)数据统一管理与控制。

    数据独立性是数据与程序间的互不依赖性,即数据库中的数据独立于应用程序而不依赖于应用程序。

    数据的独立性一般分为物理独立性与逻辑独立性两种。

    (1)物理独立性:当数据的物理结构(包括存储结构、存取方式等)改变时,其逻辑结构,应用程序都不用改变。

    (2)逻辑独立性:数据的逻辑结构改变了,如修改数据模式、增加新的数据类型、改变数据间联系等,用户的应用程序可以不变。

    【考点3】数据系统的内部结构体系

    1、数据统系统的三级模式:

    (1)概念模式,也称逻辑模式,是对数据库系统中全局数据逻辑结构的描述,是全体用户公共数据视图。一个数据库只有一个概念模式。

    (2)外模式,外模式也称子模式,它是数据库用户能够看见和使用的局部数据的逻辑结构和特征的描述,一个概念模式可以有若干个外模式。

    (3)内模式,内模式又称物理模式,它给出了数据库物理存储结构与物理存取方法。一个数据库只有一个内模式。

    内模式处于最底层,它反映了数据在计算机物理结构中的实际存储形式,概念模式处于中间层,它反映了设计者的数据全局逻辑要求,而外模式处于最外层,它反映了用户对数据的要求。

    2、数据库系统的两级映射 (详见教材第55页)

    两级映射保证了数据库系统中数据的独立性。

    (1)概念模式到内模式的映射。该映射给出了概念模式中数据的全局逻辑结构到数据的物理存储结构间的对应关系;

    (2)外模式到概念模式的映射。概念模式是一个全局模式而外模式是用户的局部模式。一个概念模式中可以定义多个外模式,而每个外模式是概念模式的一个基本视图。

    【考点4】数据模型的基本概念

    数据模型按不同的应用层次分为:

    概念数据模型:简称概念模型,是一种面向客观世界,面向用户的模型,不涉及具体的硬件环境和平台也与具体的软件环境无关的模式,它是整个数据模型的基础。

    逻辑数据模型:又称数据模型,它是一种面向数据库的模型。分为层次模型,网状模型,关系模型和面向对象模型,其中层次模型和网状模型统称为非关系模型。层次模型用树型结构表示实体之间联系的模型。

    物理数据模型:又称物理模型,它是一种面向计算机物理表示的模型。

    【考点5】E—R模型

    1、E-R模型的基本概念

    (1)实体:现实世界中的事物可以抽象成为实体,实体是概念世界中的基本单位,它们是客观存在的且又能相互区别的事物。

    (2)属性:现实世界中事物均有一些特性,这些特性可以用属性来表示。

    (3)码:唯一标识实体的属性集称为码。

    (4)域:属性的取值范围称为该属性的域。

    (5)联系:在现实世界中事物间的关联称为联系。

    两个实体集间的联系实际上是实体集间的函数关系,这种函数关系可以有下面几种:一对一的联系、一对多或多对一联系、多对多。

    2、E-R模型的的图示法

    E-R模型用E-R图来表示,E-R图包含了表示实体集、属性和联系的方法。

    (1)实体的表示:用矩形表示实体集,在矩形内写上该实体集的名字。

    (2)属性的表示:用椭圆形表示属性,在椭圆形内写上该属性的名称。

    (3)联系的表示:用菱形表示联系,菱形内写上联系名。

    【考点6】层次模型和网状模型

    层次模型是有根的定向有序树,是数据库系统中最早出现的数据模型。网状模型对应的是有向图。

    层次模型和网状模型各自应满足的条件

    模型名称

    满足的条件

    层次模型

    (1)有且只有一个结点没有双亲结点,这个结点称为根结点

    (2)根以外的其他结点有且只有一个双亲结点

    网状模型

    (1)允许一个以上的结点无双亲

    (2)一个结点可以有多于一个的双亲

    【考点7】关系模型及相关概念

    关系模式采用二维表来表示,由关系数据结构,关系操纵和关系完整性约束3部分组成,关系数据库中,用来表示实体间联系的是关系。

    关系:一个关系对应一张二维表。一个关系就是一个二维表,但是一个二维表不一定是一个关系。

    元组:表中的一行即为一个元组。

    属性:表中的一列即为一个属性,给每一个属性起一个名称即属性名。

    分量:元组中的一个属性值,是不可分割的基本数据项。

    域:属性的取值范围。

    在二维表中惟一标识元组的最小属性值称为该表的键或码。二维表中可能有若干个健,它们称为表的候选码或候选健。从二维表的所有候选键选取一个作为用户使用的键称为主键或主码。表A中的某属性集是某表B的键,则称该属性值为A的外键或外码。

    关系操纵:数据查询、数据的删除、数据插入、数据修改。

    关系模型允许定义三类数据约束,它们是实体完整性约束、参照完整性约束以及用户定义的完整性约束。其中实体完整性约束、参照完整性约束必须满足的完整性约束条件。参照完整性约束不允许关系应用不存在的元组。实体完整性约束要求关系的主键中属性值不能为空,这是数据库完整性的最基本要求。

    【考点8】关系代数

    关系代数是一种抽象的查询语言,关系代数的运算对象是关系,运算结果也是关系。运算对象,运算符和运算结果是运算的三大要素。集合运算符,专门的运算符,算术比较符和逻辑运算符。

    关系模型的基本运算:(1)插入  (2)删除   (3)修改  (4)查询(包括投影、选择、笛卡尔积运算)还有扩充运算交、除、连接及自然连接运算。

    关系代数的5个基本操作中并,差,交,笛卡尔积是二目运算。

    设关系R和S具有相同的关系模式

    1、并:R和S的并是由属于R或属于S的所有元组构成的集合。

    2、差:R和S的差是由属于R但是不属于S的元组构成的集合

    3、笛卡尔积:设R和S的元数分别为r和s,R和S的笛卡尔积是一个(r+s)元的元组集合,每个元组的前r个分量来自R的一个元组,后s个分量来自S的一个元组。运算后得到的新表的元组数是R*S,属性是r+s。

    4、交:属于R又属于S的元组构成的集合。

    5、投影:一元运算,对一个关系进行垂直切割,消去某些列,并重新按排列的顺序。

    6、选择:一元运算,根据某些条件对关系进行水平分割。即选择符合条件的元组。

    7、除:给定关系R(X,Y)和S(Y,Z),其中X,Y,Z是属性组,R中的Y和S中Y可以有不同的属性名,但必须出自相同的域集。

    8、连接:也称θ连接运算,是一种二元运算,它的操作是从两个关系的笛卡尔积中选取属性间满足一定条件的元组,以合并成一个大关系。连接运算包括等值连接和不等值连接。连接运算后得到的新表的属性是运算前表中属性相加。即多于原来关系中属性的个数。

    9、自然连接:自然连接满足的条件是(1)两关系间有公共域(2)通过公共域的相等值进行连接。

    【考点9】数据库设计和管理

    数据库设计中有两种方法,面向数据的方法和面向过程的方法。

    面向数据的方法是以信息需求为主,兼顾处理需求;面向过程的方法是以处理需求为主,兼顾信息需求。由于数据在系统中稳定性高,数据已成为系统的核心,因此面向数据的设计方法已成为主流。

    数据库设计目前一般采用生命周期法,即将整个数据库应用系统的开发分解成目标独立的若干阶段。它们是:需求分析阶段、概念设计阶段、逻辑设计阶段、物理设计阶段。

    一个低一级范式的关系模式,通过模式分解可以转化为若干个高一级范式的关系模式的集合,这种过程就叫规范化。

    概念结构设计是将需求分析阶段得到的用户需求抽象为信息结构即概念模型的过程,它是整个数据库设计的关键。

    逻辑结构设计的任务是将E—R图转换成关系数据模型的过程。

    数据库的物理结构是指数据库在物理设备上的存储结构和存取方法。它依赖于给定的计算机系统。

    常用的存取方法:索引方法,聚簇方法和HASH方法。

    数据库管理的内容:

    (1)数据库的建立,它是数据库管理的核心,包括数据模式的建立和数据加载。

    (2)数据库的重组。

    (3)数据库安全性控制。

    (4)数据库的完整性控制,数据库的完整性是指数据的正确性和相容性。

    (5)数据库的故障恢复。

    (6)数据库监控。

     

    展开全文
  • 锁的状态总共有四种:无锁状态、偏向锁、轻量锁和重量锁。随着锁的竞争,锁可以从偏向锁升级到轻量锁,再升级的重量锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)
  • 愤怒!竟然还有学校还在教 Java 的 Swing

    万次阅读 多人点赞 2021-05-24 08:34:36
    昨天,有个读者私信我说,“老师正在教 Swing,这个...但我内心其实是非常愤怒的,都什么时候了,Java 中的 Swing 早被淘汰了,哪个项目还会用这玩意编写客户端界面呢! 学 Swing、AWT 这些图形化组件纯属浪费时间! 可
  • Java学习之java高级特性

    万次阅读 多人点赞 2018-04-13 11:11:30
    下面是个人的总结 一、集合框架及泛型1、集合框架是一套性能优良、使用方便的接口和类(位于java.util包中)解决数组在存储上不能很好适应元素数量动态变化,查找效率低的缺陷集合接口: Map、Collection(子接口List...
  • 高级JAVA开发 MQ部分

    千次阅读 2019-05-15 02:18:43
    高级JAVA开发 MQ部分MQMQ的作用、为什么要用MQ常见的MQ的优缺点使用MQ带来的问题以及处理办法MQ带来的问题列举消息重复消费(幂)问题消息丢失问题消息顺序性问题消息过期丢失、大量积压问题如何保证MQ高可用性...
  • java源码包3

    千次下载 热门讨论 2013-04-20 11:30:13
    util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转,可以参考代码加以...
  • 一般的java项目后台什么技术?

    千次阅读 2020-04-30 19:35:41
    一般的java项目后台什么技术,比如Spring MVC,shiro 还有什么技术? 最近自己了几个Java Web项目,有公司的商业项目,也有个人着玩的小项目,写篇文章记录总结一下收获,列举出在项目的整个过程中,所...
  • JAVA高级面试题——2019

    万次阅读 多人点赞 2019-07-13 16:28:02
    Redis持久化为什么会降低性能? Redis哨兵机制? RabbitMq如何高可用? RabbitMq死信队列原理,应用场景? RabbitMq如何保证消费顺序? RabbitMq如何解决消息丢失?重复消费? Mybatis缓存怎么用? Mysql如何...
  • 通往高级 Java 开发的必经之路

    千次阅读 多人点赞 2018-01-12 00:00:00
    本文来自作者 大闲人柴毛毛 在 GitChat 上分享 「深入浅出 Java 虚拟机 · 通往高级 Java 开发的必经之路」,「阅读原文」查看交流实录。「文末高能」编辑 | 哈比一、JVM 内存模型Java 虚拟机(Java Virtual ...
  • 再网上看了很多的java面试题,有很多是零零碎碎的,有或者是需要付费加密????的,加个vip什么的,故而以下是博主整理的有关java面试题的以下内容,我想以一种幽默风趣????的风格来给大家分享和探讨。另外附加有...
  • Java 16 虽然是 2021 年 3 月 16 号发布的最新正式版本,但 6 个月后也要停止更新了,虽然这个版本带来了很多漂亮的新特性,但生命周期有限,对 Java 8 的伤害性有限。 自从 JDK 1.0 发布以来,Java 已经发布了数次...
  • 深入理解Java并发之synchronized实现原理

    万次阅读 多人点赞 2017-06-04 17:44:44
    【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) ... 出自【zejian的博客】...深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深...
  • 一、java的体系结构: 1、Java程序首先由编译器转换为标准字节代码,然后由虚拟机来解释执行  Applet是java的一类特殊应用程序,它潜入HTML中,可以实现多媒体的用户界面...3java类库的核心是java包,javax扩展...
  • 简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!...
  • Java高级开发岗位笔试题和解析(一)

    万次阅读 2020-04-14 09:11:22
    以下题目不要求全部回答,尽可能多的回答即可。笔试时间为 1个小时。祝你闯关成功 闯关人:田超凡 闯关时间:20191128 游戏结果:85 L3 PASS 失败数:1 ThreadPool线程池的使用 1. Java 基础部分 1.1 ...
  • 工作了3年的JAVA程序员应该具备什么技能?

    千次阅读 多人点赞 2017-02-11 22:13:08
    工作了3年的JAVA程序员应该具备什么技能 因为和同事有约定再加上LZ自己也喜欢完一件事之后进行总结,因此有了这篇文章。这篇文章大部分内容是面向整个程序员群体的,当然因为LZ本身是做Java开发的,因此有...
  • 文章目录全国计算机等级考试二 JAVA笔试试题及答案(第套一))一、选择题(每小题 2 分,共 70 分)二、填空题二 java 答案全国计算机等级考试二 JAVA笔试试题及答案(第二套)一、选择题二、填空题二级Java答案 ...
  • 后台是选择Java 、Go ,还是 PHP?

    万次阅读 2019-05-08 08:00:00
    温馨提示请拖动到文章末尾,长按识别「抽奖」小程序。现金红包你来拿。【公众号回复“1024”,送你一个特别推送】我们知道,大部分有过4年以上的工作经验的前端最起码接触过...
  • 大学四年零基础自学Java的路线

    万次阅读 多人点赞 2020-09-02 12:14:16
    JAVA的基础也一样重要,面向对象(包括类、对象、方法、继承、封装、抽象、 多态、消息解析),常见API,数据结构,集合框架,设计模式(包括创建型、结构型、行为型),多线程和并发,I/O流,Stream,网络编程你...
  • 最近看了很多简历,很多候选人年限不小,但是是一些非常传统的项目,想着也不能通过简历就直接否定一个人,何况现在大环境越来 越难,大家找工作也不容易,...
  • Java基础高级面试题整理总结

    千次阅读 2018-03-26 13:42:01
    本博客面试题大多参考骆昊的博客,再加上我进行技术培训的时候整理的面试...1)抽象:抽象是将一类对象的共同特征总结出来构造类的过程2)继承:继承是从已有的类中得到继承信息创建新类的过程3)封装:封装是把数据...
  • 我们在学习使用Java的过程中,一般认为new出来的对象是被分配在堆上,但是这个结论不是那么的绝对,通过对Java对象分配的过程分析,可以知道有两个地方会导致Java中new出来的对象并不一定分别在所认为的堆上。...
  • 本系列文章我们我们将会覆盖一些高级的Java概念,我们假设你对Java语言已经有一些基础知识。本系列文章并不是一个完整的参考,而是一个将您的Java技能提升到下一个级别的详细指南。Java是面向对象的编程语言,所以新...
  • java源码包---java 源码 大量 实例

    千次下载 热门讨论 2013-04-18 23:15:26
    util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印图片的路径,水印一般格式是gif,png,这种图片可以设置透明度、水印旋转,可以参考代码加以...
  • 有时候的确是这样啊,总想着条件更好了再干,准备完全了再开始,结果好多想法、好多事情不了了之。读完本文你将了解: 什么是注解 Java 内置的注解 个用于通知编译器信息的注解 个用于修饰注解的注解 自定义一...
  • 手把手教你用Java设计并实现一个城市公交查询系统

    千次阅读 多人点赞 2020-12-19 10:11:33
    为了使得我国公交乘客出行及查询有关信息更方便,本文运用JAVA语言技术,Jsp技术,Mysql数据库开发了B/S结构的城市公交查询系统。 该系统顺应了时代发展且具有以下优点:首先,方便乘客的出行,乘客不用询问站牌工作...
  • Java介绍

    万次阅读 2018-12-16 20:56:20
     其中Java语言是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 340,136
精华内容 136,054
关键字:

java等保3级都需要做些什么

java 订阅