JAVA部分:html
Stream 是 Java8 中处理集合的关键抽象概念,它能够指定你但愿对集合进行的操做,能够执行很是复杂的查找、过滤和映射数据等操做。使用Stream API 对集合数据进行操做,就相似于使用 SQL 执行的数据库查询。也可使用 Stream API 来并行执行操做。简单来讲,Stream API 提供了一种高效且易于使用的处理数据的方式。java
线程: 每一个进程中至少包含一个线程,而这些线程都在共享进程的资源空间等,当线程发生变化的时候只会引发CPU执行的过程发生变化,不会改变进程所拥有的资源。进程中执行运算的最小单位,亦是执行处理机调度的基本单位程序员
进程: 每一个进程都有本身的地址空间,资源如,内存,I/O,CPU,同一个进程里的 线程共享本进程里的地址空间,那能不能使用别人家进程的地址空间呢,显然这是不能够的。算法
1. 管道(PIPE) 管道是一种半双工的通讯方式,数据只能单向流动,并且只能在具备亲缘关系的进程间使用。进程的亲缘关系一般是指父子进程关系。 2. 命名管道(FIFO) 名管道也是半双工的通讯方式,可是它容许无亲缘关系进程间的通讯。 3. 信号(Signal) 用于通知接收进程某个事件已经发生,主要做为进程间以及同一进程不一样线程之间的同步手段。 4. 信号量(Semaphore) 信号量是一个计数器,能够用来控制多个进程对共享资源的访问。它常做为一种锁机制,防止某进程正在访问共享资源时,其余进程也访问该资源。 5. 消息队列(MessageQueue) 消息队列是消息的链表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。 6. 共享内存(Shared Memory) 共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。 特色: 共享内存是最快的一种 IPC,由于进程是直接对内存进行存取。 由于多个进程能够同时操做,因此须要进行同步。 信号量+共享内存一般结合在一块儿使用,信号量用来同步对共享内存的访问。 7. 套接字(Socket) 套接字也是一种进程间通讯机制,与其余通讯机制不一样的是,它可用于不一样机器间的进程通讯sql
1、传统线程通讯synchronized + wait + notify编程
Object类的wait()、notify() 、notifyAll()三个方法必须由同步监视器对象来调用,分两种状况:设计模式
a)同步方法,该类默认实例(this)就是同步监视器,能够在同步方法中能够直接调用数组
b)同步代码块,同步监视器是synchronized后括号里的对象,因此必须使用此对象调用这三个方法缓存
2、使用Condition控制线程通讯lock + condition + await + signal
Lock代替同步方法或同步代码块,Condition替代同步监视器的功能。
private final Lock lock = newReentrantLock();
private final Condition con =lock.newCondition();
lock.lock(); con.await(); con.signalAll(); lock.unlock():
3、使用阻塞队列(BlockingQueue)控制线程通讯
BlockingQueue接口主要做为线程同步的工具。当生产者试图向BlockingQueue中放入元素,若是队列已满,则线程被阻塞;当消费者试图向BlockingQueue中取出元素时,若该队列已空,则线程被阻塞。
答:
链表与数组的主要区别:
(1)数组的元素个数是固定的,而组成链表的结点个数可按须要增减;
(2)数组元素的存储单元在数组定义时分配,链表结点的存储单元在程序执行时动态向系统申请:
(3)数组中的元素顺序关系由元素在数组中的位置(即下标)肯定,链表中的结点顺序关系由结点所包含的指针来体现。
(4)对于不是固定长度的列表,用可能最大长度的数组来描述,会浪费许多内存空间。
(5)对于元素的插人、删除操做很是频繁的列表处理场合,用数组表示列表也是不适宜的。若用链表实现,会使程序结构清晰,处理的方法也较为简便。
链表与数组的联系:
ArrayList数组和LinkedList链表都是不一样步的,也就是不保证线程安全。
从逻辑结构来看
数组必须事先定义固定的长度(元素个数),不能适应数据动态地增减的状况。当数据增长时,可能超出原先定义的元素个数;当数据减小时,形成内存浪费;数组能够根据下标直接存取。
链表动态地进行存储分配,能够适应数据动态地增减的状况,且能够方便地插入、删除数据项。(数组中插入、删除数据项时,须要移动其它数据项,很是繁琐)链表必须根据next指针找到下一个元素
从内存存储来看
(静态)数组从栈中分配空间, 对于程序员方便快速,可是自由度小
链表从堆中分配空间, 自由度大可是申请管理比较麻烦
从上面的比较能够看出,若是须要快速访问数据,不多或不插入和删除元素,就应该用数组;相反, 若是须要常常插入和删除元素就须要用链表数据结构了。
答:
1、线程安全在三个方面体现
1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操做,(atomic,synchronized);
2.可见性:一个线程对主内存的修改能够及时地被其余线程看到,(synchronized,volatile);
3.有序性:一个线程观察其余线程中的指令执行顺序,因为指令重排序,该观察结果通常杂乱无序,(happens-before原则)。 解决方法:
对非安全的代码进行加锁控制;
使用线程安全的类;
多线程并发状况下,线程共享的变量改成方法级的局部变量。
一、同步方法
synchronized关键字修饰方法。因为java的每一个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,须要得到内置锁,不然就处于阻塞状态。
二、同步代码块
synchronized关键字修饰的语句块。被该关键字修饰的语句块会自动加上内置锁,从而实现同步
三、使用特殊域变量(volatile)实现线程同步
a.volatile关键字为域变量的访问提供一种免锁机制
b.使用volatile修饰域至关于告诉虚拟机该域可能被其余现象更新
c.所以每次使用该域就要从新计算,而不是使用寄存器中的值
d.volatile不会提供任何原子操做,它也不能用来修饰final类型的变量
4:使用重入锁实现线程同步
在javaSE5.0新增了一个java.concurrent包来支持同步。ReentrantLock类能够重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具体相同的基本行为和语义,而且扩展了其能力
5.使用局部变量实现线程同步
若是使用ThreadLocal管理变量,则每个使用变量的线程都得到该变量的副本,副本之间相互独立,这样每个线程均可以随意修改本身的变量副本,而不会对其余线程产生影响。
1.自定义线程池
继承Thread类
实现Runnable接口
实现Callable接口
线程池:提供了一个线程队列,队列中保存着全部等待状态的线程。避免了建立与销毁额外开销,提升了响应的速度。
1.继承Thread类实现多线程
2.覆写Runnable()接口实现多线程,然后一样覆写run().推荐此方式
3.覆写Callable接口实现多线程(JDK1.5)
4.经过线程池启动多线程
1.单个任务处理的时间比较短 2.将需处理的任务的数量大
线程池作的工做主要是控制运行的线程的数量,处理过程当中将任务放入队列,而后在线程建立后启动这些任务,若是线程数量超过了最大数量超出数量的线程排队等待,等其它线程执行完毕,再从队列中取出任务来执行。
线程池由任务队列和工做线程组成,它能够重用线程来避免线程建立的开销,在任务过多时经过排队避免建立过多线程来减小系统资源消耗和竞争,确保任务有序完成
ThreadPoolExecutor 继承自 AbstractExecutorService 实现了 ExecutorService 接口,ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor 实现了 ExecutorService 和 ScheduledExecutorService 接口
实现原理: JVM 是经过进入、退出 对象监视器(Monitor) 来实现对方法、同步块的同步的,而对象监视器的本质依赖于底层操做系统的 互斥锁(Mutex Lock) 实现。
具体实现是在编译以后在同步方法调用前加入一个monitor.enter
指令,在退出方法和异常处插入monitor.exit
的指令。
对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程monitor.exit
以后才能尝试继续获取锁。
1.目的: 为何要上锁,主要仍是多线程的缘由。多线程可能对同一块数据同时操做,数据可能会异常,好比,一个map,A线程把对键值对删除,B线程读取键值对,而后段错误就产生了。
被synchronized修饰的代码段能够防止被多个线程同时执行,必须一个线程把synchronized修饰的代码段都执行完毕了,其余的线程才能开始执行这段代码。
volatile关键字的做用就是保证了可见性和有序性(不保证原子性),若是一个共享变量被volatile关键字修饰,那么若是一个线程修改了这个共享变量后,其余线程是立马可知的。
synchronized 多用于在多个线程中须要对同一段数据进行访问时候,出现的不安全状况。由于多个线程执行同一段代码会形成数据不安全,因此须要用synchronized来同步代码。
一、可重入性:
从名字上理解, ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,二者关于这个的区别不大。二者都是同一个线程每进入一次,锁的计数器都自增1,因此要等到锁的计数器降低为0时才能释放锁。
二、锁的实现:
Synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的,有什么区别,说白了就相似于操做系统来控制实现和用户本身敲代码实现的区别。前者的实现是比较难见到的,后者有直接的源码可供阅读。
三、性能的区别:
在Synchronized优化之前,synchronized的性能是比ReenTrantLock差不少的,可是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,二者的性能就差很少了,在两种方法均可用的状况下,官方甚至建议使用synchronized,其实synchronized的优化我感受就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。
四、功能区别:
便利性:很明显Synchronized的使用比较方便简洁,而且由编译器去保证锁的加锁和释放,而ReenTrantLock须要手工声明来加锁和释放锁,为了不忘记手工释放锁形成死锁,因此最好在finally中声明释放锁。
五、锁的细粒度和灵活度:
很明显ReenTrantLock优于Synchronized
答:
两个线程会依次执行,说明产生互斥,由于实例方法加锁针对的是实例对象,当前对象调用一个synchronized方法时,其余同步方法须要等待其执行结束并释放锁以后才能执行。
两个/多个线程占有锁的前提又去得到其余锁,这样形成的线程无限的循环等待,产生了死锁!
答:
答:
Java 集合类型分为 Collection 和 Map,它们是 Java 集合的根接口,这两个接口又包含了一些子接口或实现类。
答:
**1.**从结构实现来说,HashMap是数组+链表+红黑树(链表长度大于8时转换成红黑树,小于6时变为单项链表)(JDK1.8增长了红黑树部分)实现的
2. map.put(k,v)实现原理:
第一步:首先将k,v封装到Node对象当中(节点)。
第二步:它的底层会调用K的hashCode()方法得出hash值。
**第三步:**经过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上若是没有任何元素,就把Node添加到这个位置上。若是说下标对应的位置上有链表。此时,就会拿着k和链表上每一个节点的k进行equal。若是全部的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
3. map.get(k)实现原理:
**第一步:**先调用k的hashCode()方法得出哈希值,并经过哈希算法转换成数组的下标。
**第二步:**经过上一步哈希算法转换成数组的下标以后,在经过数组下标快速定位到某个位置上。重点理解若是这个位置上什么都没有,则返回null。若是这个位置上有单向链表,那么它就会拿着参数K和单向链表上的每个节点的K进行equals,若是全部equals方法都返回false,则get方法返回null。若是其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是咱们要找的value了,get方法最终返回这个要找的value。
由于equals默认比较是两个对象内存地址
HashMap默认的“加载因子”是0.75,默认的容量大小是16;增长容量时,每次将容量变为“原始容量x2”。
Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不能够为null。此外,Hashtable中的映射不是有序的。
1 继承和实现方式不一样
HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口。 Hashtable 继承于Dictionary,实现了Map、Cloneable、java.io.Serializable接口。
2 线程安全不一样
Hashtable的几乎全部函数都是同步的,即它是线程安全的,支持多线程。 而HashMap的函数则是非同步的,它不是线程安全的。
3 对null值的处理不一样
HashMap的key、value均可觉得null。 Hashtable的key、value都不能够为null。
4 遍历方式不一样
HashMap只支持Iterator(迭代器)遍历。此种迭代方式,HashMap是“从前向后”的遍历数组;Hashtabl是“从后往前”的遍历数组;而Hashtable支持Iterator(迭代器)和Enumeration(枚举器)两种方式遍历。
5 添加元素时的hash值算法不一样
HashMap添加元素时,是使用自定义的哈希算法。
Hashtable没有自定义哈希算法,而直接采用的key的hashCode()。
6 容量的初始值和增长方式不同
HashMap默认的“加载因子”是0.75,默认的容量大小是16;增长容量时,每次将容量变为“原始容量x2”。 Hashtable默认的“加载因子”是0.75,默认的容量大小是11;增长容量时,每次将容量变为“原始容量x2 + 1”。
HashMap不是线程安全的;而ConcurrentHashMap 是线程安全的,可是效率有点慢
不是线程安全的;
一、继承HashMap,重写或者按要求编写本身的方法,这些方法要写成synchronized,在这些synchronized的方法中调用HashMap的方法 二、使用Collections.synchronizedMap() 三、使用ConcurrentHashMap替代,并不推荐新代码使用Hashtable,HashTable继承于Dictionary,任意时间只有一个线程能写Hashtable,并发性能不如ConcurrentHashMap,由于ConcurrentHashMap引入了分段锁。不须要线程安全的场景使用HashMap,须要线程安全的场合使用ConcurrentHashMap替换。
大体区别:
1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 (LinkedList是双向链表,有next也有previous)
2.对于随机访问get和set,ArrayList以为优于LinkedList,由于LinkedList要移动指针。
3.对于新增和删除操做add和remove,LinedList比较占优点,由于ArrayList要移动数据。
Vector:就比Arraylist多了个同步化机制(线程安全)。
Hashtable:就比Hashmap多了个线程安全。
ConcurrentHashMap:是一种高效可是线程安全的集合。
Stack:栈,也是线程安全的,继承于Vector。
Vector(白客特)、HashTable、Properties是线程安全的;
ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是线程不安全的。
Vector(白客特)
根据JVM规范,JVM 内存共分为五类:虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。
内存区域是指 Jvm 运行时将数据分区域存储。
整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Useing)、卸载(Unloading)7个阶段。其中验证、准备和解析3个部分统称为链接(Linking),
加载
“加载”是“类加载”过程的一个阶段,由类加载器来完成,主要作如下3件事:
验证
验证是链接阶段的第一步,这一阶段的目的是为了确保Class文件的二进制字节流中包含的信息符合当前虚拟机的要求,而且不会危害虚拟机自身的安全。
主要进行以下4个验证:
准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段, 这些变量所使用的内存都将在方法区中进行分配。
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程
初始化
类初始化阶段是类加载过程的最后一步,在这一阶段才开始执行类中定义的Java代码(字节码)。初始化阶段是执行类构造器 ()方法(类构造器就是“类变量的赋值动做+静态语句块”)的过程。
JVM 内存共分为五类:虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。其中程序计数器、虚拟机栈、本地方法栈3个区域随线程而生、随线程而灭,所以这几个区域的内存分配和回收都具有肯定性,就不须要过多考虑回收的问题,由于方法结束或者线程结束时,内存天然就跟随着回收了。而Java堆区和方法区则不同、不同!(怎么不同说的朗朗上口),这部份内存的分配和回收是动态的,正是垃圾收集器所需关注的部分。
Java中标记垃圾的算法主要有两种, 引用计数法和可达性分析算法。
引用计数法:
引用计数法就是给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任什么时候候计数器为 0 的对象就是不可能再被使用的,能够当作垃圾收集。
可达性分析算法:
这个算法的基本思想就是经过一系列的称为 “GC Roots” 的对象做为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证实此对象是不可用的。
Java中存在着四种垃圾回收算法,标记清除算法、复制算法、标记整理算法以及分代回收算法。
1.标记清除算法
该算法分为“标记”和“清除”两个阶段:标记阶段的任务是标记出全部须要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。它是最基础的收集算法
2.复制算法
为了解决效率问题,咱们开发出了复制算法。它能够将内存分为大小相同的两块,每次使用其中的一块。当第一块的内存使用完后,就将还存活的对象复制到另外一块去,而后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
简单来讲就是该对象分为对象面以及空闲面,对象在对象面上建立,对象面上存活的对象会被复制到空闲面,接下来就能够清除对象面的内存。
3.标记整理算法
为了解决复制算法的缺陷,充分利用内存空间,提出了标记整理算法。该算法标记阶段和标记清除同样,可是在完成标记以后,它不是直接清理可回收对象,而是将存活对象都向一端移动,而后清理掉端边界之外的内存。
4.分代收集算法
当前虚拟机的垃圾收集都采用分代收集算法,这种算法就是根据具体的状况选择具体的垃圾回收算法。通常将 java 堆分为新生代和老年代,这样咱们就能够根据各个年代的特色选择合适的垃圾收集算法。
**答:**由于 StringBuffer 的全部公开方法都是 synchronized 修饰的
**答:区别1:**StringBuffer:线程安全,StringBuilder:线程不安全。由于 StringBuffer 的全部公开方法都是 synchronized 修饰的,而 StringBuilder 并无 synchronized修饰。
**区别2:**缓冲区 StringBuffer 每次获取 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串。而 StringBuilder 则每次都须要复制一次字符数组,再构造一个字符串。因此,缓存冲这也是对 StringBuffer 的一个优化吧,不过 StringBuffer 的这个toString 方法仍然是同步的。
**区别3:**既然 StringBuffer 是线程安全的,它的全部公开方法都是同步的,StringBuilder 是没有对方法加锁同步的,因此毫无疑问,StringBuilder 的性能要远大于 StringBuffer。
所谓的反射机制就是java语言在运行时拥有一项自观的能力。经过这种能力能够完全的了解自身的状况为下一步的动做作准备。
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method。
Java反射的做用:在Java运行时环境中,对于任意一个类,能够知道这个类有哪些属性和方法。对于任意一个对象,能够调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。能够对流化后的对象进行读写操做,也可将流化后的对象传输于网络之间。
一、抽象类能够提供某些方法的部分实现,而接口不能够;
二、抽象类是单个继承机制,其子类不必定要实现父类中的全部没实现的方法,而接口一个类能够有多个接口,而且方法都要实现。
冒泡排序、快速排序
最根本的区别在因而否真正获取一个对象的复制实体,而不是引用
深拷贝(deepCopy)是增长了一个指针而且申请了一个新的内存,使这个增长的指针指向这个新的内存,
能够对程序做出解释,方便被其余程序(编辑器)读取
MD5
不可逆的
不能够,覆盖(override)是在继承+多态的前提下的概念。Java中的静态方法很少态,因此不涉及覆盖,不管静态方法是在基类仍是派生类上。
封装的概念
封装性是面向对象编程的核心思想
指的就是将描述某种实体的数据和基于这些数的操做集合到一块儿,造成一个封装体
封装的思想保证了类内部数据结构的完整性,使用户没法轻易直接操做类的内部数据,这样下降了对内部数据的影响,提升了程序的安全性和可维护性。
继承的概念
继承是Java面向对象编程技术的一块基石,由于它容许建立分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具备父类的实例域和方法,或类从父 类继承方法,使得子类具备父类相同的行为。
多态的概念
多态指的就是在应用程序中出现的“ 重名 ” 现象。多态性容许以统一的风格编写程序,以处理种类繁多的已存在的类及其相关类。这样既下降了维护难度,又节省了时间
建立者模式又叫建造者模式,是将一个复杂的对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示。建立者模式隐藏了复杂对象的建立过程,它把复杂对象的建立过程加以抽象,经过子类继承或者重载的方式,动态的建立具备复合属性的对象。
在用户不知道对象的建造过程和细节的状况下就能够直接建立复杂的对象。
方便用户建立复杂的对象(不须要知道实现过程)
代码复用性 & 封装性(将对象构建过程和细节进行封装 & 复用)
1.普通索引index :加速查找 2.惟一索引 主键索引:primary key :加速查找+约束(不为空且惟一) 惟一索引:unique:加速查找+约束 (惟一) 3.联合索引 -primary key(id,name):联合主键索引 -unique(id,name):联合惟一索引 -index(id,name):联合普通索引 4.全文索引fulltext :用于搜索很长一篇文章的时候,效果最好。 5.空间索引spatial :了解就好,几乎不用
(频繁改动和删除的数据、数据量小、区分度小的字段(好比性别))
(不知足最左前缀原则、where 后面不能用函数)