赞
踩
JVM
JVM也是一个软件,不同的平台有不同的版本。我们编写的Java源码,编译后会生成一种 .class 文件,称为字节码文件。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码然后运行。也就是说,只要在不同平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的Java程序。
而这个过程中,我们编写的Java程序没有做任何改变,仅仅是通过JVM这一”中间层“,就能在不同平台上运行,真正实现了”一次编译,到处运行“的目的。
JVM是一个”桥梁“,是一个”中间件“,是实现跨平台的关键,Java代码首先被编译成字节码文件,再由JVM将字节码文件翻译成机器语言,从而达到运行Java程序的目的。
注意:编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过JVM翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却不一样。
所以,运行Java程序必须有JVM的支持,因为编译的结果不是机器码,必须要经过JVM的再次翻译才能执行。即使你将Java程序打包成可执行文件(例如 .exe),仍然需要JVM的支持。
注意:跨平台的是Java程序,不是JVM。JVM是用C/C++开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的JVM。
事务的四大特征
ORM
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单来说,将程序中的兑现自动持久化到关系数据库中。那么,到底如何实现持久化呢?一种简单的反感是采用硬编码的方式(jdbc操作sql方式),为每一种可能的数据库访问操作提供单独的方法。这种方法存在很多缺陷,所以使用ORM框架(为了解决面型对象与关系数据库存在的互不匹配的现象的框架)来解决。
同步代码块、同步方法
get 和 post 请求
但是GET和POST只是HTTP协议中的两种发送请求的方法,HTTP的底层是TCP/IP。所以GET和POST的底层也是TCP/IP,也就是说,GET/POST都是TCP链接。GET和POST能做的事情是一样一样的。你要给GET加上request body,给POST带上url参数,技术上是完全行的通的。
html 和 jsp
html的优点:
html的缺点:
jsp的优点:
jsp的缺点:
锁
1、公平锁/非公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁。 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。 对于Java ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。 对于Synchronized而言,也是一种非公平锁。由于其并不像ReentrantLock是通过AQS(AbstractQueuedSynchronizer)的来实现线程调度,所以并没有任何办法使其变成公平锁。
2、可重入锁
可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。说的有点抽象,下面会有一个代码的示例。 对于Java ReentrantLock而言, 他的名字就可以看出是一个可重入锁,其名字是Re entrant Lock重新进入锁。 对于Synchronized而言,也是一个可重入锁。可重入锁的一个好处是可一定程度避免死锁。
- synchronized void setA() throws Exception{
- Thread.sleep(1000);
- setB();
- }
-
- synchronized void setB() throws Exception{
- Thread.sleep(1000);
- }
3、独享锁/共享锁
对于Java ReentrantLock而言,其是独享锁。但是对于Lock的另一个实现类ReadWriteLock,其读锁是共享锁,其写锁是独享锁。 读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的。 独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。 对于Synchronized而言,当然是独享锁。
4、互斥锁/读写锁
上面讲的独享锁/共享锁就是一种广义的说法,互斥锁/读写锁就是具体的实现。
5、乐观锁/悲观锁
乐观锁与悲观锁不是指具体的什么类型的锁,而是指看待并发同步的角度。
从上面的描述我们可以看出,悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多的场景,不加锁会带来大量的性能提升。 悲观锁在Java中的使用,就是利用各种锁。 乐观锁在Java中的使用,是无锁编程,常常采用的是CAS算法,典型的例子就是原子类,通过CAS自旋实现原子操作的更新。
6、分段锁
分段锁其实是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。
我们以ConcurrentHashMap来说一下分段锁的含义以及设计思想,ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap(JDK7与JDK8中HashMap的实现)的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)。
当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在那一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入。
但是,在统计size的时候,可就是获取hashmap全局信息的时候,就需要获取所有的分段锁才能统计。
分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。
7、偏向锁/轻量级锁/重量级锁
这三种锁是指锁的状态,并且是针对Synchronized。在Java 5通过引入锁升级的机制来实现高效Synchronized。这三种锁的状态是通过对象监视器在对象头中的字段来表明的。
8、自旋锁
在Java中,自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。 典型的自旋锁实现的例子,可以参考自旋锁的实现
Hibernate 和 MyBatits
相同点:
都是java中的orm框架,屏蔽jdbc的api底层访问细节,使我们不用域jdbc的挨批打交道,就可以完成对数据的持久化操作。jdbc的api编程流程固定,还将sql与java代码混在在一起,经常需要拼凑sql语句,细节繁琐,开发不方便。
Mybatis的好处:
屏蔽jdbc api的底层访问细节,将sql语句域java代码分离,提供将结果集自动封装为实体对象和对象的集合的功能,queryForList返回对象集合。用queryForObject返回单个对象。提供自动将实体对象的属性传递给sql语句的参数。
Hibernate的好处:
Hibernate是一个全自动的偶人吗映射工具,它可以自动生成sql语句,执行并返回java结果。
不同点:
集合
HashMap内部实现原理
1、initialCapacity:初始容量。指的是 HashMap 集合初始化的时候自身的容量。可以在构造方法中指定;如果不指定的话,总容量默认值是 16 。需要注意的是初始容量必须是 2 的幂次方。
2、size:当前 HashMap 中已经存储着的键值对数量,即 HashMap.size()
3、loadFactor:加载因子。所谓的加载因子就是 HashMap (当前的容量/总容量) 到达一定值的时候,HashMap 会实施扩容。加载因子也可以通过构造方法中指定,默认的值是 0.75 。举个例子,假设有一个 HashMap 的初始容量为 16 ,那么扩容的阀值就是 0.75 * 16 = 12 。也就是说,在你打算存入第 13 个值的时候,HashMap 会先执行扩容。
4、threshold:扩容阀值。即 扩容阀值 = HashMap 总容量 * 加载因子。当前 HashMap 的容量大于或等于扩容阀值的时候就会去执行扩容。扩容的容量为当前 HashMap 总容量的两倍。比如,当前 HashMap 的总容量为 16 ,那么扩容之后为 32 。
5、table:Entry 数组。我们都知道 HashMap 内部存储 key/value 是通过 Entry 这个介质来实现的。而 table 就是 Entry 数组。
6、在 Java 1.7 中,HashMap 的实现方法是数组 + 链表的形式。上面的 table 就是数组,而数组中的每个元素,都是链表的第一个结点。
7、如果 table 数组为空时先创建数组,并且设置扩容阀值;如果 key 为空时,调用 putForNullKey 方法特殊处理;计算 key 的哈希值;根据第三步计算出来的哈希值和当前数组的长度来计算得到该 key 在数组中的索引;遍历该数组索引下的整条链表,如果之前已经有一样的 key ,那么直接覆盖 value ;如果该 key 之前没有,那么就进入 addEntry 方法。下面就来看一下 addEntry 方法。
8、在 Java 1.8 中,如果链表的长度超过了 8 ,那么链表将转化为红黑树;发生 hash 碰撞时,Java 1.7 会在链表头部插入,而 Java 1.8 会在链表尾部插入;在 Java 1.8 中,Entry 被 Node 代替(换了一个马甲)。
step1:如果传入的key为空,那么返回空键对应的值(HashMap允许一个null键)。
step2:把key的hashcode经过一个hash算法,得到一个hash值。
step3:根据上一步得到的hash值定位数组的下标。
step4:上一步定位到数组的下标的位置如果有元素,取第一个元素,判断他们的hash值是否相同,如果相同,再判断两个对象是否相等。如果hash值不同,或hash值相同,却不相等,判断第二个元素。直到判断完所有的元素。
step5:把当前元素作为数组下标位置的第一个元素,把之前的元素设为新插入元素的next节点,判断是否超过threshold,超过则扩容(addEntry逻辑说明)。
我们把key看成是一个人,key的hashCode看成是人的姓名,value看成是电话号码。假如我现在要存张三的电话号码,那么,对应的:
step2:把姓名按照首字母划分,得到hash值为Z。
step3:找到Z所在的位置。
step4:判断Z位置处第一个元素(假设Z位置处只有一个赵六),赵六的hash值也为Z,所以,继续比较到底是不是我要找的张三,ok,不是,判断Z位置处不存在第二个元素,执行step5。
step5:在Z位置处插入张三和他的电话号码,把赵六移到他的后面。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。