java 随记
后台开发的过程中积累的关于java的杂记
架构
SSH框架
为什么要分层?
因为分层使代码变得清晰,容易写也容易阅读,更重要的是让代码扩展性更好,层与层之间的改动不会互相影响
各层的分工
- dao——与数据库交互
- service——处理业务逻辑,调用dao层方法
- action——用来控制转发,接到请求交给service处理
dao是用于操作数据用的,service是为页面功能服务的,在service中对数据进行处理计算,然后返回数据结果到ACTION,而action则再对数据进一步处理,比如把list转成json,把两个service数据进行合并等,并发送到jsp页面显示。
并发相关
ReentrantLock
- lock之后要自己unlock
- lock相比synchronized更加灵活,可以通过trylock判断锁是不是被占用了,在被占用的情况下可以忙其他事,而不是直接就阻塞了
- lock持有的是对象监视器,也就是类似于syncronized(this){} ,但是需要注意这两者持有的对象监视器是不同的
- lock配置Condition的signal和await可以实现syncronized的wait和notify来实现等待/通知模型,相比之下Condition更灵活:一个lock实例可以创建多个Condition实例,实现多路通知和有选择性的通知,而不是像notify一样是由jvm随机选择的
BlockingQueue
概念
阻塞队列是一种支持当获取元素时会阻塞直到队列不为空,当插入元素时阻塞直到队列有空间。
方法
操作阻塞队列有四种形式的方法,add/remove/element抛出异常,offer/poll/peek返回具体值,put/take阻塞,offer(e, time, unit)、poll(time, unit)指定等待的最长时间
不同实现
- ArrayBlockingQueue 只有一个锁,通过两个condition来实现阻塞、通知,添加和删除数据时只允许一个被执行
- LinkedBlockingQueue 有两个锁,putLock和takeLock,各自维护一个condition,添加和删除数据可以允许并行,当然删除和添加最多各自有一个线程在执行。
- LinkedBlockingQueue 不仅在消费数据的时候进行唤醒插入阻塞的线程,而且在插入如果容量还没满,也会唤醒插入阻塞的线程
jvm原理
垃圾回收
参考深入理解java垃圾回收机制
垃圾回收就是java中的一个亮点(有利有弊),通过一定的算法自动管理对象的生命周期,防止内存泄漏(内存对象的生命周期超过了程序需要它的时长)
垃圾回收的算法有:
- 引用计数:早期的算法,通过给堆中的每个对象内置一个引用计数器来实现(缺点是:无法检测循环引用)
- 标志、清洗算法
- 分代收集:频繁收集新生代,比较少的收集老生代,基本不收集持久代(分代回收的GC分为 minor gc 和 full/major gc,以下为两种gc的日志格式)
- GC:
- FULL GC:
- 新的对象都在eden区上创建,当eden区的大小达到阈值就会发生GC,eden区中存活的对象会复制到survivor区,并清除eden中无效的对象,如果survivor区中的对象达到年龄限制或者大小达到阈值,就会将存活的对象复制到old区,如果这时old区空间不足就会发生full gc,full gc之后old区的空间仍然无法承载young区要晋升的对象大小,就会发生OOM
内存分配
内存分为 heap、stack、method
heap:
- 堆存放的都是对象,空间大但是访问慢(时空守恒)
- 为所有线程所共享
- java heap主要分成三种:
- young:主要用来存放新生的对象
- old: 主要用来存放生命周期长的内存对象
- permanent:主要用来存放类和方法的元数据信息和常量池 ,类被加载后就放入这个区域。GC不会对持久层进行清理,
- metaspace:在java8中持久代已经被移除了,因为持久代的大小是固定的,所以在类加载很多的情况下,容易出现OOM:PermGen space错误,类和方法的元数据被移入元数据区。(存在于本地内存中,所以大小只受物理内存的影响)元数据区是自动增长的,通过-XX:MaxMetaSpaceSize来限制Metaspace的大小,以前的Perm参数失效,超过最大值将会在metaspace发生full gc收集dead class或者classloader
stack:
- 栈区放的都是基础数据类型和对象的引用
- 保存函数调用的现场
method:
- 方法区也为所有线程所共享(另一种说法也就是permanent区)
- 方法区存放的都是在整个程序中永远唯一的元素,包括class、static变量
- 常量池也是方法区的一部分,存放程序中的字面量如”hello“ 以及常量
java 集合框架
哈希结构
哈希表的数组长度为什么总是习惯用2^n?
hash 的时候总是需要对对象的hashCode取哈希表长度的模,对于2^n 取模,可以简化为 hash & (2^n - 1),提高效率
jdk1.8中的hashmap中的 hash算法是什么?有什么优点?
hash算法是(h = key.hashCode()) ^ (h >>> 16) ,通过这样hash,高位的变化反映到低位里,这样我们取模的时候hash & (length - 1) 就不会只取低位相关,防止有些hashCode只和高位相关造成的冲突过多
hashtable、hashmap、concurrenthashmap 哈希家族的异同点
- 都是继承于map接口,用于存储键值对。hashtable是同步的,如果不需要线程安全,推荐使用hashmap代替hashtable,如果需要高并发线程安全的实现,使用ConcurrentHashMap代替hashtable
- 集合方法返回的iterators是“fail-fast”的,也就是说当hash结果被修改,除了通过iterator的remove方法外的改动,都会造成iterator抛出ConcurrentModificationException异常。因此,在并发修改的情况下,iterator很快失败并清除,而不是冒险在未来不确定的时间做不确定的事。hashtable的方法返回的emurations却不是fail-fast的
- hashmap可以接受null值,hashtable则不行
- HashMap可以通过下面的语句进行同步:Map m = Collections.synchronizeMap(hashMap);
ConcurrentHashMap(面试必考)
concurrentHashMap是一个并发的hash表的实现,它支持完全的并发读取,支持大数量的并发更新操作。
高性能的原因:
- 用分离锁实现多个线程间的更深层次的共享访问,不再是只有一个线程能同时持有容器的锁了。
- 利用hashEntry的不变性(final hash,key,next)来降低读操作对加锁的需求
- 用volatile变量协调读写线程间的内存可见性
缺点
- 返回的迭代器是弱一致性的,fail-safe并且不会抛出ConcurrentModificationException异常
源码分析(基于jdk1.7)
concurrentHashMap是由segment数组和hashEntry数组组成的,segment是一种可重入锁ReentranLock,在CHM中扮演锁的角色,HashEntry用于存储键值对数据。一个CHM中包含一个segment数组,segment的结构和hashmap类似,一个segment中包含一个hashEntry数组,每个HashEntry都是一个链表的结构,每个segment守护着自己的hashEntry数组,要往这一段hashEntry数组中修改,必须先获得相应的锁
arrayList、linklist、vector
- arrayList 内部用数组实现,随机访问和遍历快,插入删除慢
- linklist 内部用链表实现,适合数据的动态插入和删除,随机访问和遍历慢
- vector 跟 arraylist差不多,除了以下几点
- vector是线程安全的,因此访问速度也较慢
- arraylist在内存不够时扩展50% + 1个,vector默认扩展一倍
java 代码执行顺序
JAVA类首次装入时,会对静态成员变量或方法进行一次初始化,但方法不被调用是不会执行的,静态成员变量和静态初始化块级别相同,非静态成员变量和非静态初始化块级别相同。
初始化顺序:先初始化父类的静态代码--->初始化子类的静态代码-->(创建实例时,如果不创建实例,则后面的不执行)初始化父类的非静态代码(变量定义等)--->初始化父类构造函数--->初始化子类非静态代码(变量定义等)--->初始化子类构造函数
tips:
若子类没有显示调用父类的构造函数,则默认调用父类的无参构造函数,如果父类没有则编译错误
java 命令行参数
-classpath
java 通过指定-classpath 来指定虚拟机搜索的你要运行的类的目录、jar文件名、zip文件名,之间用;(linux 用:)隔开。否则java查不到你的class文件就会报java.lang.NoClassDefFoundError异常,在运行时可以通过System.getProperty(“java.class.path”)得到jvm查找类的路径
也可以通过CLASSPATH环境变量来指定类搜索路径,建议用-cp-DpropertyName=value
系统属性,可以通过System.getProperty(propertyName)获取value的值,用来设置全局变量值,如配置文件路径-Xms -Xmx 堆的最大最小值
-Xss 线程堆的最大值
--XX:+HeapDumpOnOutOfMemoryError
当JVM不断地抛出OutOfMemory错误的时候,该命令会通知JVM拍摄一个“堆转储快照”, 并通过-XX:HeapDumpPath 指定该文件的保存路径,可以方便调试问题-XX:+UseParNewGC 使用多线程并发处理新生代GC
-XX:+UseConcMarkSweepGC 使用CMS并发处理GC
-Djava.awt.headless=true 无头模式,系统的配置模式,在该模式下,系统缺少了显示、键盘或鼠标。据说
在Java服务器程序需要进行部分图像处理功能时,建议将程序运行模式设置为headless,这样有助于服务器端有效控制程序运行状态和内存使用(可防止在处理大图片时发生内存溢出)
泛型
- 上界:表示对泛型的限制,传进来的对象必须是class 或者 class 的子类
- 通配符
- java5之后添加了通配符 和 泛型(泛型我们是了解的),通配符的基本用法
GenericType<?>
GenericType<? extends upperBoundType> // 设置上界
GenericType<? super lowerBoundType> // 设置下界
- 看了下 在 [Java 的泛型类型中使用通配符 - 博客频道 - CSDN.NET](https://app.yinxiang.com/shard/s15/nl/2659954/653fb6e2-ea9d-48f2-b4cf-5d5f749923fb/),觉得通配符主要是方便了**泛型对象作为方法参数可以引用泛型子类**,代码如下:
List<? extends Number> nums = new ArrayList<>();
List<Integer> ints = Arrays.asList(1, 2);
List<Double> doubles = Arrays.asList(1.1, 2.2);
nums.addAll(ints);
nums.addAll(dbls); // addAll 方法使用了通配符作为参数
}
// print all Number 或 Number 子类的list, 如果没有通配符的话, 估计得一个一个子类都去实现以下。。。
public void print(List<? extends Number> list) {
list.forEach(x -> System.out.println(x));
}
- 通配符的限制:
- 不能用来直接创建变量对象
- 不能进行修改操作,例如下面的代码,编译器可能觉得,鬼知道你引用了哪个子类呢
List<? extends Number> nums = new ArrayList<Integer>();
nums.add(1); // 编译错误
java 基础概念
- 守护线程: 只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作。当最后一个守护线程结束时,守护线程随同JVM一起结束工作。最典型的例子就是GC
- volatile:
- 用在多线程中,同步变量。一般情况下线程为了提高效率,会缓存主内存中的变量在自己的线程栈中,volatile声明的变量则不能缓存,保证了线程之间的变量一致性[虽然自己测不出这个效果。。。]
- 不能保证线程安全。引用例子如下
假如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值,在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6;线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6;导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况。
- 创建对象:
创建对象有哪些方法?
最普通的new(给对象分配空间,调用构造函数初始化,返回引用)
调用对象的clone方法
- clone给对象分配空间后,直接在内存上对已有对象影印,不需要构造函数
- 需要实现CloneAble接口才能调用对象的clone方法,clone是一种浅复制,例如对象中包含一个String,那么新的对象中的String 跟原来的指向同一个字符串。
- 要实现深复制,需要实现clone方法,不仅clone本身,还需要包含的引用对象
运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。【没玩过】
访问修饰符: 只有private在同一个包内不能访问,其他包的只能public能访问
日志操作
log4j
log4j 使用写日志变得很简单,支持多个输出和格式化
log4j 主要由三个部分组成 logger 、appender、 layout
- logger 负责日志的收集,主要由rootlogger 和 其他各个类的logger组成,通过logger.info等方法来记录消息,子logger中可以自定义各种配置,如果没有设置就会向上级的logger查找相应的配置,最上层为rootlogger
- appender负责日志的输出,可以输出到文件、控制台、数据库、kafka等等
- layout绑定到相应的的appender来格式化它的日志输出格式,丰满多姿
java 随记的更多相关文章
- Java入门记(五):容器关系的梳理(下)——Map
注意:阅读本文及相关源码时,需要数据结构相关知识,包括:哈希表.链表.红黑树. Map是将键(key)映射到值(value)的对象.不同的映射不能包含相同的键:每个键最多只能映射到一个值.下图是常见M ...
- Java入门记(四):容器关系的梳理(上)——Collection
目录 一.Collection及子类/接口容器继承关系 二.List 2.1 ArrayList 2.1.1 序列化的探讨 2.1.2 删除元素 2.1.3 调整大小 2.2 Vector和Stack ...
- Java入门记(三):初始化顺序
初始化顺序的规则 1.在一个类的对象实例化时,成员变量首先初始化,然后才调用构造器,无论书写顺序.如果调用构造器前,没有显式初始化,那么会赋默认值. 这样做法的原因可以理解为:构造器执行时可能会用到一 ...
- Java入门记(二):向上转型与向下转型
在对Java学习的过程中,对于转型这种操作比较迷茫,特总结出了此文.例子参考了<Java编程思想>. 目录 几个同义词 向上转型与向下转型 例一:向上转型,调用指定的父类方法 例二:向上转 ...
- Java入门记(一):折腾HelloWorld
HelloWorld,学习每门语言的第一步.有人戏称,这些年的编程生涯就是学习各种语言的HelloWorld,不知是自谦还是自嘲.目前所在的公司使用Java作为主要开发语言,我进行语言转换也大半年了, ...
- Java琐记
svn项目倒入,所选的文件夹一定是src上面以及的:然后eclipse会自动创建一个项目,项目名称就是src上级文件夹的名称:然后会按照路径下的文档结构如导入到eclipse的结构中: 被标记为// ...
- java随记2
1.Arrays java8里新添加了parallelSort等parallel开头的方法,表示利用cpu并行的能力 2.面向对象 如果继承树里的某个类要被初始化时,系统将会同时初始化该类的所有父类 ...
- java随记 2月16
1.a=a+b 等于 a+=b ,且a+=b隐含强制类型转换 2.^ 表示异或 两个二进制同号为假,异号为真 即 0^0=0,1^1=0,0^1=1 3.三元运算 布尔表达式 ?表达式 ...
- java面试记很多次还是记不住的问题
1.java底层如何实现多态 https://blog.csdn.net/fan2012huan/article/details/51007517 (1)在常量池中找到方法调用的符号引用 (2)查看P ...
随机推荐
- 为异常处理做准备,熟悉一下WinDbg工具
为异常处理做准备,熟悉一下WinDbg工具 马上开始异常处理第二讲,但是在讲解之前,还有熟悉一下我们的WinDbg工具,当然你如果熟悉这个工具,那么就可以不用看了. 一丶熟悉WinDbg界面 刚开始打 ...
- 这家IT教育公司太拼了:毕业生找不到工作就全额退学费!
乐橙谷为了让更多的学生有工作,有高薪工作,已经决定尝试一种更刺激的游戏规则:完成课时的学员如果毕业找不到工作,公司将全额退还学费.这家公司秉承着自己的使命:以尊重的文化,敬畏的心态去努力帮助每个学生实 ...
- 全面了解Android热修复技术
WeTest 导读 本文探讨了Android热修复技术的发展脉络,现状及其未来. 热修复技术概述 热修复技术在近年来飞速发展,尤其是在InstantRun方案推出之后,各种热修复技术竞相涌现.国内大部 ...
- 点击截图功能 js canvas
使用:html2canvas实现浏览器截图 <html> <head> <meta name="layout" content="main& ...
- 关于API,前后端分离
之前再开放新型web项目和app时,遇到了和前后端交互的问题.总所周知的是,web前后端交接时,最重要的交互方式的接口的制定. 而关于接口的规定,衍生出了一大堆问题,第一是关于空值的制定,是不输出呢? ...
- SQL Server 2016 Alwayson新增功能
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/ 概述 SQLServer2016发布版本到现在已有一年多的时间了,目前最新的稳定版本是SP1版本.接下来就开看看2016在Alw ...
- BCB中AnsiString类方法小结
AnsiString类是BCB中最常见类之一,了解它对以后深入学习BCB大有帮助. 介绍AnsiString类之前,先要介绍一些背景知识.VCL(Visual Component Library 可视 ...
- Javascript 中 ==(相等运算符) 和 ===(严格相等运算符) 区别
在JS中,"==="叫做严格运算符,"=="叫做相等运算符. 它们的区别是相等运算符(==)比较两个值是否相等,严格相等运算符(===)比较它们是否为" ...
- Reverse Words in a String III
Given a string, you need to reverse the order of characters in each word within a sentence while sti ...
- margin:0px auto和text-align:center区别
(1)margin:0px auto :作用于块级元素,对块级元素进行居中 (2)text-align:center:作用于内联元素,必须放在要居中的内联元素所在的块级元素. 例: (1) <d ...