主要内容是ehcache,字符串优化,核心数据结构(有concurrenthashmap)+部分代码优化方法
1.ehcache
首先buffer(缓冲区)与cache(缓存区)都是内存的一块区域
buffer是将多个待写入磁盘的数据在此区域缓冲一下然后在某时刻一次性写入到磁盘中,这样可以大大减少对于磁盘设备的IO操作.
cache是将磁盘中经常被访问的数据放入到缓存区,那么访问此类数据就不需要再到磁盘中去找而直接在cache中便可命中,这会大大提高系统的性能
package yarnsls.javaFile.com;
import java.io.File;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.PersistentCacheManager;
import org.ehcache.StateTransitionException;
import org.ehcache.Status;
import org.ehcache.config.Builder;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.Configuration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.EntryUnit;
import org.ehcache.config.units.MemoryUnit;
// 需要导入ehcache和slf4j两个包
public class testcache {
public static void main(String[] args) {
//test1---------------
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured", // 缓存名
CacheConfigurationBuilder
.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(100))// 缓冲堆里元素的个数
.build())
.build(true);// 初始化
// 从缓存管理器中获得预定缓存
Cache<Long, String> preConfigured = cacheManager.getCache("preConfigured", Long.class, String.class);
// 新建一个缓存
Cache<Long, String> myCache = cacheManager.createCache("myCache", CacheConfigurationBuilder
.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(100)).build());
myCache.put(1L, "Hello World!");
String value = myCache.get(1L);
System.out.println(value);
cacheManager.close();
System.exit(0);
//test2------------------
PersistentCacheManager persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.with(CacheManagerBuilder.persistence(getStoragePath() + File.separator + "myData"))
.withCache("threeTieredCache", // 缓存别名
CacheConfigurationBuilder.newCacheConfigurationBuilder(Integer.class, String.class,
ResourcePoolsBuilder.newResourcePoolsBuilder().heap(10, EntryUnit.ENTRIES) // 堆
.offheap(1, MemoryUnit.MB) // 堆外
.disk(20, MemoryUnit.GB) // 磁盘
)).build(true);
Cache<Integer, String> threeTieredCache = persistentCacheManager.getCache("threeTieredCache", Integer.class,
String.class);
// 读
for (int i = 0; i <= 20000; i++) {
threeTieredCache.put(i, "$" + i);
}
// 写
for (int i = 0; i <= 200000; i++) {
String value01 = threeTieredCache.get(i);
System.out.println("get at " + i + ":" + value01);
}
persistentCacheManager.close();
}
private static String getStoragePath() {
// TODO Auto-generated method stub
return "d:";
}
}
对象池
https://blog.csdn.net/liuxiao723846/article/details/78881040
字符串优化处理
substring,concat,replace等都有潜在的内存泄漏。(空间换时间,有内存溢出的问题)
split("[; |, | :]")实现了用分号逗号和冒号分割整个字符串,方法简单但在性能敏感的系统中频繁使用不可取。
StringTokenizer专门用来处理字符串分割子串的工具类。(public StringTokenizer(String str,String delim))delim是分割符号。
使用indexOf和subString配合,自己编写的字符串截取。
charAt,indexOf和subString执行速度快,可作为高频使用
+和+=应该尽量少用,concat效果高于前者,有远低于stringbuilder
如能预估stringbuilder的大小,可以提高性能(扩容是将容量翻倍,建立新的char[],将原数组复制过去,涉及大量内存复制操作)
核心数据结构
List:
vector线程安全,ArrayList不是线程同步的。vector每一个操作都加锁了,会额外增加很多开销。在增加或删除元素上,LinkedList性能远优于ArrayList(后者需要大量的复制操作,链表则不需要)
ArrayList默认扩充容量为原容量的1.5倍
map:
hashtable大部分方法做了同步,不允许key或者value为空值
hashmap线程不安全,key和value可以为空。
hashmap扩容:超过阈值(阈值=总容量*负载因子;负载因子=元素个数/数组总大小),每次扩容一倍。
concurrenthashmap:1.7之前使用segment。1.8回归数值链表,实现线程安全时使用了synchronization和csa等方法,没有使用重入锁。
重入锁:http://www.cnblogs.com/gxyandwmm/p/9387833.html
红黑树:https://blog.csdn.net/UzV80PX5V412NE/article/details/78505761
理解的一般,下面两个博客写的较好,可以细节研究下。
http://www.importnew.com/28263.html
https://www.cnblogs.com/nullzx/p/8647220.html
linkedhashmap:在增加了一个链表,存放元素输入的顺序。
treemap:可以对元素进行排序,comparable或者comparator。
set:基本都是对map的封装,和相应的map类一一对应
优化集合访问:在不影响系统结构的前提下减少方法的调用(消耗堆栈,会牺牲部分性能)
改善性能技巧:
慎用异常;
局部变量的访问速度远远高于类成员变量;
位运算代理乘除法;
替换swith(下图,数组访问要快很多);
提取表达式;
展开循环(但会影响代码的可读性和可维护性),eg:一个循环干两个循环的事;
布尔运算代替位运算;
数组复制使用arraycopy(),System.arraycopy()为native函数,通常native函数性能要优于普通函数;
使用buffer进行i/o操作,outputstream,inputstream;
Object.clone()可以绕过对象构造函数,快速复制一个对象实力,但生成的实例只是原对象的浅拷贝,深拷贝需要重新实现clone方法;新(拷贝产生)、旧(元对象)对象不同,但是内部如果有引用类型的变量,新、旧对象引用的都是同一引用。深拷贝:全部拷贝原对象的内容,包括内存的引用类型也进行拷贝。
https://www.cnblogs.com/acode/p/6306887.html
就方法调用速度而言,静态方法明显快于实例方法,所以对于一些工具类,应该使用static方法实现
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中,其他变量,如静态变量、实例变量等都在堆中创建,速度较慢。