graph LR
A-->B
public class Singleton{
private Singleton(){
System.out.println("Singleton is create");//创建单例可能比较慢,应为是大对象。
}
private static Singleton instance = new Singleton();
public Singleton getInstance(){
return instance;
}
}
public class SingletonStr {
private SingletonStr(){
System.out.println("SingletonStr is create");
}
private static SingletonStr instance = new SingletonStr();
public static SingletonStr getInstance(){
return instance;
}
public static void createString(){
System.out.println("createString in singleton");
}
public static void main(String[] args) {
SingletonStr.createString();
}
}
/***
*输出如下:
* SingletonStr is create
* createString in singleton
***/
public class LazySingleton {
private LazySingleton(){
System.out.println("LazySingleton is create");
}
private static LazySingleton instance = null;
public static LazySingleton getInstance(){
if(instance == null){
synchronized (LazySingleton.class){
if(instance == null){
instance = new LazySingleton();
}
}
}
return instance;
}
}
public class StaticSingleton {
private StaticSingleton(){
System.out.println("StaticSingleton is create");
}
private static class SingletionHolder{
private static StaticSingleton instance = new StaticSingleton();
}
public static StaticSingleton getInstance(){
return SingletionHolder.instance;
}
}
public class JdkDBQueryHandler implements InvocationHandler {
IDBQuery real = null;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(real == null){
real = new DBQueryImpl();
}
return real;
}
}
public static IDBQuery createJdkproxy(){
IDBQuery jdkProxy = (IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{IDBQuery.class},new JdkDBQueryHandler());
return jdkProxy;
}
}
public class CglibDBQueryInsterceptor implements MethodInterceptor {
IDBQuery real = null;
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(real == null){
real = new DBQueryImpl();
}
return real;
}
}
public static IDBQuery createCGlibProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setCallback(new CglibDBQueryInsterceptor());
enhancer.setInterfaces(new Class[]{enhancer.createClass()});
IDBQuery cglibProxy = (IDBQuery) enhancer.create();
return cglibProxy;
}
public static IDBQuery createJavassistBytecodeDynamicProxy()
throws NotFoundException, CannotCompileException, IllegalAccessException, InstantiationException {
ClassPool mpool = new ClassPool(true);
CtClass mCtc = mpool.makeClass(IDBQuery.class.getName() + "JavassistBytecodeProxy");
mCtc.addInterface(mpool.get(IDBQuery.class.getName()));
mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));
mCtc.addField(CtField.make("public "+IDBQuery.class.getName()+ " real;", mCtc));
String dbqueryname = DBQueryImpl.class.getName();
mCtc.addMethod(CtNewMethod.make("public String request(){if(real == null) real = new "
+ dbqueryname + "(); return real.request();}",mCtc));
Class pc = mCtc.toClass();
IDBQuery bytecodeProxy = (IDBQuery) pc.newInstance();
return bytecodeProxy;
}
public interface IReportManager {
public String createReport();
}
public class EmployeeReportManager implements IReportManager {
private String tenantId;
public EmployeeReportManager(String tenantId){
this.tenantId = tenantId;
}
@Override
public String createReport() {
return "is employee";
}
}
public class FinancialReportManager implements IReportManager {
private String tenantId;
public FinancialReportManager(String tenantId){
this.tenantId = tenantId;
}
@Override
public String createReport() {
return "is financial";
}
}
//工厂方法
public class ReportManagerFactory {
Map<String, IReportManager> financialMap = new HashMap<>();
Map<String, IReportManager> empolyeeMap = new HashMap<>();
public IReportManager getFinancialReportManager(String tenantId){
if(!financialMap.containsKey(tenantId)){
IReportManager financialReportManager = new FinancialReportManager(tenantId);
financialMap.put(tenantId, financialReportManager);
return financialReportManager;
}
return financialMap.get(tenantId);
}
public IReportManager getEmployeeReportReportManager(String tenantId){
if(!empolyeeMap.containsKey(tenantId)){
IReportManager employeeReportManager= new EmployeeReportManager(tenantId);
empolyeeMap.put(tenantId, employeeReportManager);
return employeeReportManager;
}
return empolyeeMap.get(tenantId);
}
}
//使用
public class MainTest {
public static void main(String[] args) {
ReportManagerFactory reportManagerFactory = new ReportManagerFactory();
IReportManager reportManager = reportManagerFactory.getFinancialReportManager("A");
System.out.println(reportManager.createReport());
}
}
装饰者模式基本设计准则 合成/聚合复用原则的思想,代码复用,应该尽可能的使用委托,而不是使用继承。因为继承是一种紧密耦合,任何父类的改动都会影响子类,不利于系统维护,而委托则是松耦合,只要接口不变,委托类的改动并不会影响其上层对象。
装饰者模式通过委托机制,复用系统中各个组件,在运行时,可以将这些功能进行叠加,从而构造一个超级对象,使其拥有各个组件的功能。基本结构如下
装饰者Decorator在被装饰者ConcreteComponent的基础上(拥有相同接口Component)添加自己的新功能,被装饰者拥有的是系统核心组件,完成特定功能模板。如下案例:
//接口
public interface IPacketCreator {
public String handleContent();
}
//被装饰者
public class ConcreteComponent implements IPacketCreator {
@Override
public String handleContent() {
return "Content of packet";
}
}
//装饰器
public abstract class PacketDecorator implements IPacketCreator {
IPacketCreator component;
public PacketDecorator(IPacketCreator c){
component = c;
}
}
//具体的装饰器一
public class PacketHTMLHeaderCreator extends PacketDecorator {
public PacketHTMLHeaderCreator(IPacketCreator c) {
super(c);
}
@Override
public String handleContent() {
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append("");
sb.append(component.handleContent());
sb.append("");
sb.append("");
return sb.toString();
}
}
//具体的装饰器二
public class PacketHTTPHeaderCreator extends PacketDecorator {
public PacketHTTPHeaderCreator(IPacketCreator c) {
super(c);
}
@Override
public String handleContent() {
StringBuilder sb = new StringBuilder();
sb.append("Cache-Control:no-cache\n");
sb.append(component.handleContent());
return sb.toString();
}
}
JDK的实现中也有不少组件用的装饰器模式,其中典型的就是IO模型,OutputStream,InputStream类族的实现,如下OutputStream为核心的装饰者模型的实现:
其中FileOutputStream为系统核心类,实现了文件写入数据,使用DataOutputStream可以在FileOutputStream的基础上增加多种数据类型的写操作支持。BufferOutputStream装饰器,可以多FileOutputStream增加缓冲功能,优化IO性能,以BufferedOutputStream为代表的功能组件,是将性能模块和功能模块分离的一种典型实现
public static void testIOStream() throws IOException {
DataOutputStream dataOutputStream =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("C:\\Users\\Administrator\\Desktop\\重要信息.txt")));
// 没有缓冲功能的流对象
// DataOutputStream dataOutputStream =
// new DataOutputStream(
// new FileOutputStream("C:\\Users\\Administrator\\Desktop\\重要信息.txt"));
long begin = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
dataOutputStream.write(i);
}
System.out.println("speed: " + (System.currentTimeMillis() - begin));
}
//观察者的接口
public interface Observer {
void update(Subject s);
}
//Subject顶级接口
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notivfyAllObserver();
}
//某视频网站,实现了Subject接口
public class VideoSite implements Subject {
private ArrayList<Observer> userList;
private ArrayList<String> videos;
public VideoSite() {
userList = new ArrayList<>();
videos = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
userList.add(o);
}
@Override
public void removeObserver(Observer o) {
userList.remove(o);
}
@Override
public void notivfyAllObserver() {
for (Observer observer : userList) {
observer.update(this);
}
}
public void addVideos(String video) {
this.videos.add(video);
//通知所有用户
notivfyAllObserver();
}
public ArrayList<String> getVideos() {
return videos;
}
@Override
public String toString() {
return videos.toString();
}
}
//实现观察者,即看视频的美剧迷们
public class VideoFans implements Observer {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public VideoFans(String name){
this.name = name;
}
@Override
public void update(Subject s) {
System.out.println(this.name + ", new Video are available!");
System.out.println(s);
}
}
//test
public class MainTest {
public static void main(String[] args) {
VideoSite vs = new VideoSite();
vs.registerObserver(new VideoFans("one"));
vs.registerObserver(new VideoFans("two"));
vs.registerObserver(new VideoFans("three"));
vs.addVideos("生活大爆炸大更新!!!");
}
}
public static void testIOStream() throws IOException {
DataOutputStream dataOutputStream =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("C:\\Users\\Administrator\\Desktop\\重要信息.txt")));
// 没有缓冲功能的流对象
// DataOutputStream dataOutputStream =
// new DataOutputStream(
// new FileOutputStream("C:\\Users\\Administrator\\Desktop\\重要信息.txt"));
long begin = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
dataOutputStream.write(i);
}
System.out.println("speed: " + (System.currentTimeMillis() - begin));
}
public BufferedOutputStream(OutputStream out);
public BufferedOutputStream(OutputStream out, int size)
public interface ObjectPool<T> extends Closeable {
......
T borrowObject() throws Exception, NoSuchElementException, IllegalStateException;
......
void returnObject(T var1) throws Exception;
}
public interface PooledObjectFactory<T> {
//定义如何创建新对象实例
PooledObject<T> makeObject() throws Exception;
//对象从对象池中被销毁时,会执行这个方法。
void destroyObject(PooledObject<T> p) throws Exception;
//判断对象是否可用
boolean validateObject(PooledObject<T> p);
//在对象从对象池取出前,会激活这对象
void activateObject(PooledObject<T> p) throws Exception;
//在对象返回对象池时候被调用
void passivateObject(PooledObject<T> p) throws Exception;
}
//方法一
temp = a;
a = b;
b = temp;
//方法二
a = a+b;
b = a-b;
a = a-b;
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str1 == str3.intern());
}
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
.....
}
public String substring(int beginIndex, int endIndex)
String x= "abcdef";
x= str.substring(1,3);
System.out.println(x);
//输出:ab
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > count) {
throw new StringIndexOutOfBoundsException(endIndex);
}
if (beginIndex > endIndex) {
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
}
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value); //使用的是和父字符串同一个char数组value
}
//构造方法
String(int offset, int count, char value[]) {
this.value = value;
this.offset = offset;
this.count = count;
}
//案例
String str = "abcdefghijklmnopqrst";
String sub = str.substring(1, 3);
str = null;
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
//构造函数
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
public static char[] copyOfRange(char[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0)
throw new IllegalArgumentException(from + " > " + to);
char[] copy = new char[newLength];
System.arraycopy(original, from, copy, 0,
Math.min(original.length - from, newLength));
return copy;
}
public String[] split(String regex)
public static void main(String[] args) {
String orgStr = null;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 10000; i++) {
stringBuilder.append(i);
stringBuilder.append(";");
}
orgStr = stringBuilder.toString();
Long timeBegin = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
orgStr.split(";");
}
Long timeEnd = System.currentTimeMillis();
System.out.println("speed :" + (timeEnd - timeBegin));
Long timeBegin1 = System.currentTimeMillis();
StringTokenizer st = new StringTokenizer(orgStr, ";");
for (int i = 0; i < 10000; i++) {
while (st.hasMoreTokens()){
st.nextToken();
}
st = new StringTokenizer(orgStr, ";");
}
Long timeEnd2 = System.currentTimeMillis();
System.out.println("speed2 :" + (timeEnd2 - timeBegin1));
}
//输出
speed :3162
speed2 :2688
Long timeBegin2 = System.currentTimeMillis();
String tmp = orgStr;
while (true){
String splitStr = null;
int j = tmp.indexOf(";");
if(j<0) break;
splitStr = tmp.substring(0,j);
tmp = tmp.substring(j+1);
}
Long timeEnd2 = System.currentTimeMillis();
System.out.println("speed2 :" + (timeEnd2 - timeBegin2));
//输出
speed2 :94
public char charAt(int index);
//方法一
String result = "String" +"and" + "String" + "append";
//方法二
StringBuilder result = new StringBuilder();
result.append("String");
result.append("and");
result.append("String");
result.append("append");
String s = "StringandStringappend";
String str1 = "String";
String str2 = "and";
String str3 = "String";
String str4 = "append";
String result = str1 + str2 + str3 + str4;
String str1 = "String";
String str2 = "and";
String str3 = "String";
String str4 = "append";
String result = new StringBuilder(String.valueOf(str1)).append(str2).append(str3).append(str4);
//耗时1062ms
for (int i = 0; i < 10000; i++) {
str = str + i;
}
//耗时360ms
for (int i = 0; i < 10000; i++) {
str = str.concat(String.valueOf(i));
}
//耗时0ms
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i);
}
for (int i = 0; i < 10000; i++) {
new StringBuilder(String.valueOf(str)).append(i).append(str3).toString();
}
public StringBuilder(int capacity)
public StringBuffer(int capacity)
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
都来自AbstraList实现,AbstractList直接实现了List接口,
ArrayList和Vector都使用数组,但是Vector增加了对多线程的支持,是线程安全的,Vector绝大部分方法做了线程同步,理论上说ArrayList性能要好于Vector
LinkedList使用双向链表实现,每个元素都包含三个部分,元素内容,前驱表项,后驱表项
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
modCount++;
elementData[size++] = e;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last; //最后一个节点复制给l
final Node<E> newNode = new Node<>(l, e, null); //新节点前驱是l
last = newNode;
if (l == null)
first = newNode;//l为空标识之前没有节点,那么新节点就是首个节点
else
l.next = newNode;//l不为空,将l(此时L是之前最后一个节点) 后驱指针指向新节点。
size++;
modCount++;
}
Object obj = new Object();
for(int i=0; i<500000;i++){
last.add(obj);
}
public void add(int index, E element)
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);//数据移动拷贝
elementData[index] = element;
size++;
}
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
while(list.size() > 0){
list.remove(0);
}
while(list.size() > 0){
list.remove(list.size() >> 1);
}
while(list.size() > 0){
list.remove(list.size() - 1);
}
List类型/删除位置 | 头部 | 中部 | 尾部 |
---|---|---|---|
ArrayList | 6203 | 3125 | 16 |
LinkedList | 15 | 8781 | 16 |
List类型 | ForEach操作 | 迭代器 | for循环 |
---|---|---|---|
ArrayList | 63ms | 47ms | 31ms |
LinkedList | 63ms | 47ms | ~~无穷大 |
//ForEach
for (Iterator iterator = list.iterator(); iterator.hasNext()){
String s = (String) iterator.next();
String s1 = s;
}
//for
for (Iterator iterator = list.iterator(); iterator.hasNext()){
String s = (String) iterator.next();
}
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
//hash值获取
static final int hash(Object key) {
int h;
//调用的Object中的hashCode方法,接着对取得的Hash做移位运算,与原hash值异或(^)运算
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {//按位与操作
......
}
return null;
}
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
....
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
....
}
}
public HashMap(int initialCapacity, float loadFactor)
public HashMap(int initialCapacity)
public HashMap()
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
if (oldCap > 0) {
//超过最大值不扩容
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
//没超过,扩容为原来2倍,并且扩容后小于最大值,大于默认值16
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
//计算新的resize上线
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
//此处开始数据迁移,吧每个bucket都移动到新的buckets中
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
do {
next = e.next;
//原索引
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
//原索引+ oldCap
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
//将原索引放到bucket里面
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
//原索引+ oldCap放到bucket里面
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
public HashSet() {
map = new HashMap<>();
}
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public static void nioCopyFileTest(String source, String destination) throws IOException {
FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(destination);
FileChannel readChannel = fis.getChannel();
FileChannel writeChannel = fos.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);//申请堆内存
while (true){
byteBuffer.clear();
int len = readChannel.read(byteBuffer);
if(len == -1){
break;
}
byteBuffer.flip();
writeChannel.write(byteBuffer);
}
readChannel.close();
writeChannel.close();
}
public static void main(String[] args) {
//分配15个字节
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
System.out.println("limit: "+ byteBuffer.limit() + "capacity: "
+ byteBuffer.capacity() + "position: "+ byteBuffer.position());
for (int i = 0; i < 10; i++) {
byteBuffer.put((byte) i);
}
System.out.println("limit: "+ byteBuffer.limit() + "capacity: "
+ byteBuffer.capacity() + "position: "+ byteBuffer.position());
byteBuffer.flip();//重置position
System.out.println("limit: "+ byteBuffer.limit() + "capacity: "
+ byteBuffer.capacity() + "position: "+ byteBuffer.position());
for (int i = 0; i < 5; i++) {
System.out.println(byteBuffer.get());
}
System.out.println("limit: "+ byteBuffer.limit() + "capacity: "
+ byteBuffer.capacity() + "position: "+ byteBuffer.position());
byteBuffer.flip();
System.out.println("limit: "+ byteBuffer.limit() + "capacity: "
+ byteBuffer.capacity() + "position: "+ byteBuffer.position());
}
/**
limit: 15capacity: 15position: 0
limit: 15capacity: 15position: 10
limit: 10capacity: 15position: 0
0
1
2
3
4
limit: 10capacity: 15position: 5
limit: 5capacity: 15position: 0
*/
Buffer中放入10个byte,因此position前移10,其他两个不变
flip操作,重置position,将buffer重写模式转为读,并且limit设置到当前position位置作为读取的界限位置:
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
byte array[] = new byte[1024];
ByteBuffer b = ByteBuffer.wrap(array, 0, array.length-1);
b.rewind();
b.clear();
b.flip();
public final Buffer rewind() {
position = 0;
mark = -1;
return this;
}
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
public final Buffer mark() {
mark = position;
return this;
}
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
public static void main(String[] args) {
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
for (int i = 0; i < 10; i++) {
byteBuffer.put((byte) i);
}
byteBuffer.flip();
for (int i = 0; i < byteBuffer.limit(); i++) {
System.out.print(byteBuffer.get());
if(i == 4){
byteBuffer.mark();
System.out.println("mark at: " + i );
}
}
byteBuffer.reset();
System.out.println(" reset to mark");
while (byteBuffer.hasRemaining()){
System.out.print(byteBuffer.get());
}
}
/**
01234mark at: 4
56789reset to mark
56789
*/
public abstract ByteBuffer duplicate();
ByteBuffer byteBuffer = ByteBuffer.allocate(15);
for (int i = 0; i < 10; i++) {
byteBuffer.put((byte) i);
}
byteBuffer.position(2);
byteBuffer.limit(6);
ByteBuffer byteBuffer2 = byteBuffer.slice();
java.nio.ReadOnlyBufferException
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("D:\\sentinel.txt", "rw");
FileChannel fc = raf.getChannel();
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, raf.length());
while (mbb.hasRemaining()){
System.out.println((char) mbb.get());
}
raf.close();
}
public long read(ByteBuffer[] dsts, int offset, int length) throws IOException;
public long read(ByteBuffer[] dsts) throws IOException;
public long write(ByteBuffer[] srcs, int offset, int length)
throws IOException;
public long write(ByteBuffer[] srcs) throws IOException;
public static void main(String[] args) throws IOException {
ByteBuffer bookBuf = ByteBuffer.wrap("java性能优化技巧".getBytes("utf-8"));
ByteBuffer autBuf = ByteBuffer.wrap("葛一鸣".getBytes("utf-8"));
Integer booklen = bookBuf.limit();
Integer autlen = autBuf.limit();
ByteBuffer[] bufs = new ByteBuffer[]{bookBuf, autBuf};
File file = new File("D:\\test.txt");
if(!file.exists()){
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
FileChannel fc = fos.getChannel();
fc.write(bufs);
fos.close();
}
public static void main(String[] args) throws IOException {
ByteBuffer bookBuf = ByteBuffer.wrap("java性能优化技巧".getBytes("utf-8"));
ByteBuffer autBuf = ByteBuffer.wrap("葛一鸣".getBytes("utf-8"));
Integer booklen = bookBuf.limit();
Integer autlen = autBuf.limit();
ByteBuffer b1 = ByteBuffer.allocate(booklen);
ByteBuffer b2 = ByteBuffer.allocate(autlen);
ByteBuffer[] bufs = new ByteBuffer[]{b1, b2};
File file = new File("D:\\test.txt");
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();
fc.read(bufs);
String bookName = new String(bufs[0].array(), "utf-8");
String authname = new String(bufs[1].array(), "utf-8");
System.out.println(bookName + " : " + authname);
}
//文件写入
public static void main(String[] args) throws IOException {
long bgTime = System.currentTimeMillis();
Integer numOfInt = 4000000;
FileChannel fileChannel = new RandomAccessFile("D:\\test.txt", "rw").getChannel();
IntBuffer ib = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, numOfInt*4).asIntBuffer();
for (Integer i = 0; i < numOfInt; i++) {
ib.put(i);
}
if(fileChannel != null){
fileChannel.close();
}
System.out.println("speed: "+ (System.currentTimeMillis() - bgTime));
}
//文件读取
public static void main(String[] args) throws IOException {
long bgTime = System.currentTimeMillis();
Integer numOfInt = 4000000;
FileChannel fileChannel = new RandomAccessFile("D:\\test.txt", "rw").getChannel();
IntBuffer ib = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, numOfInt*4).asIntBuffer();
for (Integer i = 0; i < numOfInt; i++) {
ib.get();
}
if(fileChannel != null){
fileChannel.close();
}
System.out.println("speed: "+ (System.currentTimeMillis() - bgTime));
}
使用Stream | ByteBuffer | MaooedByteBuffer | |
---|---|---|---|
写耗时 | 1641 | 954 | 109 |
独耗时 | 1297 | 296 | 79 |
class DirectByteBuffer extends MappedByteBuffer implements DirectBuffer
public static void main(String[] args) throws IOException {
long begin = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
//测试一
ByteBuffer b = ByteBuffer.allocate(1000);
//测试二
ByteBuffer b = ByteBuffer.allocateDirect(1000);
}
System.out.println(System.currentTimeMillis() - begin);
}
//测试一中普通ByteBuffer结果
[GC (Allocation Failure) [PSYoungGen: 2048K->488K(2560K)] 2048K->758K(9728K), 0.0009691 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2536K->488K(2560K)] 2806K->774K(9728K), 0.0013332 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2536K->488K(2560K)] 2822K->850K(9728K), 0.0009512 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2536K->504K(2560K)] 2898K->914K(9728K), 0.0006810 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2552K->504K(2560K)] 2962K->930K(9728K), 0.0010715 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2552K->504K(1536K)] 2978K->930K(8704K), 0.0005587 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1528K->224K(2048K)] 1954K->1184K(9216K), 0.0005771 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1248K->160K(2048K)] 2208K->1160K(9216K), 0.0003433 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1184K->32K(2048K)] 2184K->1080K(9216K), 0.0002990 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1056K->32K(2048K)] 2104K->1080K(9216K), 0.0003482 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1056K->32K(2048K)] 2104K->1080K(9216K), 0.0002876 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1056K->32K(2048K)] 2104K->1080K(9216K), 0.0004324 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1056K->0K(2048K)] 2104K->1048K(9216K), 0.0003900 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1024K->32K(2048K)] 2072K->1080K(9216K), 0.0003066 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1056K->32K(2048K)] 2104K->1080K(9216K), 0.0002950 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1056K->32K(2048K)] 2104K->1080K(9216K), 0.0002153 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
18
Heap
PSYoungGen total 2048K, used 849K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
eden space 1024K, 79% used [0x00000000ffd00000,0x00000000ffdcc7d0,0x00000000ffe00000)
from space 1024K, 3% used [0x00000000fff00000,0x00000000fff08000,0x0000000100000000)
to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
ParOldGen total 7168K, used 1048K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
object space 7168K, 14% used [0x00000000ff600000,0x00000000ff7062e0,0x00000000ffd00000)
Metaspace used 3456K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 376K, capacity 388K, committed 512K, reserved 1048576K
//测试二 DirectBuffer 结果
[GC (Allocation Failure) [PSYoungGen: 2048K->488K(2560K)] 2048K->762K(9728K), 0.0011810 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (System.gc()) [PSYoungGen: 2064K->496K(2560K)] 2338K->2288K(9728K), 0.0022161 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 496K->0K(2560K)] [ParOldGen: 1792K->1482K(7168K)] 2288K->1482K(9728K), [Metaspace: 3464K->3464K(1056768K)], 0.0179332 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
47
Heap
PSYoungGen total 2560K, used 1276K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
eden space 2048K, 62% used [0x00000000ffd00000,0x00000000ffe3f278,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
ParOldGen total 7168K, used 1482K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
object space 7168K, 20% used [0x00000000ff600000,0x00000000ff772a10,0x00000000ffd00000)
Metaspace used 3475K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 377K, capacity 388K, committed 512K, reserved 1048576K
StringBuffer str = new StringBuffer("hello world");
StringBuffer str1 = str;
public class CanReliveObj {
public static CanReliveObj obj;
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("CanreliveObj finalize called");
obj = this;
}
@Override
public String toString(){
return "i am CanReliveObj";
}
public static void main(String[] args) throws InterruptedException {
obj = new CanReliveObj();
obj = null;
System.gc();
Thread.sleep(1000);
if(obj == null){
System.out.println("obj is null");
}else {
System.out.println("obj is alieve");
}
System.out.println("second gc");
// obj = null;
System.gc();
Thread.sleep(1000);
if(obj == null){
System.out.println("obj is null");
}else {
System.out.println("obj is alieve");
}
}
}
//输出
CanreliveObj finalize called
obj is alieve
second gc
obj is alieve
public class WeakHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V> {
.....
}
//案例一
public static void main(String[] args) {
Map<Integer, Byte[]> map = new WeakHashMap<>();
for (int i = 0; i < 10000; i++) {
Integer ii = new Integer(i);
map.put(ii, new Byte[i]);
}
}
//GC日志堆栈信息
[GC (Allocation Failure) [PSYoungGen: 1024K->504K(1536K)] 1024K->656K(5632K), 0.0406638 secs] [Times: user=0.00 sys=0.00, real=0.05 secs]
[GC (Allocation Failure) [PSYoungGen: 1524K->504K(1536K)] 1677K->806K(5632K), 0.0012177 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1528K->504K(1536K)] 1830K->1878K(5632K), 0.0010152 secs] [Times: user=0.11 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1526K->504K(1536K)] 2901K->3014K(5632K), 0.0010945 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1528K->504K(1536K)] 4038K->3960K(5632K), 0.0013167 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 504K->0K(1536K)] [ParOldGen: 3456K->3416K(4096K)] 3960K->3416K(5632K), [Metaspace: 3422K->3422K(1056768K)], 0.0076172 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[Full GC (Ergonomics) [PSYoungGen: 1021K->0K(1536K)] [ParOldGen: 3416K->1915K(4096K)] 4438K->1915K(5632K), [Metaspace: 3437K->3437K(1056768K)], 0.0047949 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
.....
Heap
PSYoungGen total 1536K, used 1441K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
eden space 1024K, 91% used [0x00000000ffe00000,0x00000000ffeeaae8,0x00000000fff00000)
from space 512K, 98% used [0x00000000fff00000,0x00000000fff7dd00,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 4096K, used 3114K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
object space 4096K, 76% used [0x00000000ffa00000,0x00000000ffd0a9b8,0x00000000ffe00000)
Metaspace used 3458K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 376K, capacity 388K, committed 512K, reserved 1048576K
//案例二
public static void main(String[] args) {
Map<Integer, Byte[]> map = new HashMap<>();
for (int i = 0; i < 10000; i++) {
Integer ii = new Integer(i);
map.put(ii, new Byte[i]);
}
}
[GC (Allocation Failure) [PSYoungGen: 1024K->504K(1536K)] 1024K->616K(5632K), 0.0009105 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1528K->496K(1536K)] 1640K->862K(5632K), 0.0007723 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 1518K->504K(1536K)] 1885K->1862K(5632K), 0.0011210 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
.......
[Full GC (Allocation Failure) Exception in thread "main" [PSYoungGen: 1023K->1023K(1536K)] [ParOldGen: 4091K->4091K(4096K)] 5115K->5115K(5632K), [Metaspace: 3443K->3443K(1056768K)], 0.0025873 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) java.lang.OutOfMemoryError: Java heap space
[PSYoungGen: 1023K->0K(1536K)] [ParOldGen: 4095K->874K(4096K)] 5119K->874K(5632K), [Metaspace: 3449K->3449K(1056768K)], 0.0039615 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
at com.ljm.resource.nio.WeakHashmapDemo.main(WeakHashmapDemo.java:16)
PSYoungGen total 1536K, used 66K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
eden space 1024K, 6% used [0x00000000ffe00000,0x00000000ffe10808,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 4096K, used 874K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
object space 4096K, 21% used [0x00000000ffa00000,0x00000000ffadaa08,0x00000000ffe00000)
Metaspace used 3480K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 379K, capacity 388K, committed 512K, reserved 1048576K
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;
final int hash;
Entry<K,V> next;
/**
* Creates new entry.
*/
Entry(Object key, V value,
ReferenceQueue<Object> queue,
int hash, Entry<K,V> next) {
super(key, queue);
this.value = value;
this.hash = hash;
this.next = next;
}
.....
}
private void expungeStaleEntries() {
for (Object x; (x = queue.poll()) != null; ) {
synchronized (queue) {
@SuppressWarnings("unchecked")
Entry<K,V> e = (Entry<K,V>) x;
int i = indexFor(e.hash, table.length);//找到这个表项的位置
Entry<K,V> prev = table[i];
Entry<K,V> p = prev;
while (p != null) {//移除以及被回收的表项
Entry<K,V> next = p.next;
if (p == e) {
if (prev == e)
table[i] = next;
else
prev.next = next;
// Must not null out e.next;
// stale entries may be in use by a HashIterator
e.value = null; // Help GC
size--;
break;
}
prev = p;
p = next;
}
}
}
}
//方案一
long a = 100;
for(int i=0; i<100000; i++){
a+=2;
a/=2;
}
//方案二
long a = 100;
for(int i=0; i<100000; i++){
a<<=1;
a>>=1;
}
public static void main(String[] args) {
boolean a = false;
boolean b = true;
int d = 0;
for (int i = 0; i < 1000000; i++) {
if(a&b&"javaperform".contains("java")){ //位运算
d=0;
}
}
}
public static void main(String[] args) {
boolean a = false;
boolean b = true;
int d = 0;
for (int i = 0; i < 1000000; i++) {
if(a&&b&&"javaperform".contains("java")){ //布尔运算
d=0;
}
}
}
//位运算耗时250ms
//布尔运算耗时16ms
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
public static void main(String[] args) throws Exception {
// DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("D:\\test.txt")));
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\test.txt"));
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
dos.writeBytes(String.valueOf(i) + "\r\n");
}
dos.close();
System.out.println("speed time: "+ (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
// DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("D:\\test.txt")));
DataInputStream dis = new DataInputStream(new FileInputStream("D:\\test.txt"));
while (dis.readLine() != null){
// System.out.println(dis.readLine());
}
dis.close();
System.out.println("speed time: "+ (System.currentTimeMillis() - start));
}
简单说就是一个异步获取的流程,在main函数中利用Future提交一个任务线程task,但是这个任务执行是有耗时的,并不会立刻返回,此时main函数无需等待或者阻塞,可以继续main函数之后的逻辑,等结果是必要因素的时候通过Future.get来阻塞等待获取对应信息。如下图解
如下源码,自己实现的一个Future模式实现
public interface Data {
public String getResult();
}
public class RealData implements Data {
protected final String result;
public RealData(String para){
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(para);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result = sb.toString();
}
@Override
public String getResult() {
return result;
}
}
public class FutureData implements Data {
protected RealData realData = null;
protected boolean isReady = false;
public synchronized void setRealData(RealData realData){
if(isReady){
return;
}
this.realData = realData;
isReady = true;
notifyAll();
}
@Override
public String getResult() {
while (!isReady){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return realData.result;
}
}
public class Client {
public Data request(final String queryStr){
final FutureData futureData = new FutureData();
new Thread(){
@Override
public void run(){
RealData realData = new RealData(queryStr);
futureData.setRealData(realData);
}
}.start();
return futureData;
}
}
public class MainTest {
public static void main(String[] args) {
Client client = new Client();
Data data = client.request("my name");
System.out.println("request over");
try {
System.out.println("sleep 2000ms");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("data = "+ data.getResult());
}
}
public boolean cancel(boolean mayInterruptIfRunning)
public boolean isCancelled()
public boolean isDone()
public V get() throws InterruptedException, ExecutionException
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException
public class NewRealData implements Callable<String> {
private String para;
public NewRealData(String para){
this.para = para;
}
@Override
public String call() throws Exception {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 10; i++) {
sb.append(para);
Thread.sleep(100);
}
return sb.toString();
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String> futureTask = new FutureTask<>(new NewRealData("my name"));
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.submit(futureTask);
System.out.println("request over");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("data = "+ futureTask.get());
}
public class Worker implements Runnable {
protected Queue<Object> workQueue;
protected Map<String, Object> resultMap;
public void setWorkQueue(Queue<Object> workQueue) {
this.workQueue = workQueue;
}
public void setResultMap(Map<String, Object> resultMap) {
this.resultMap = resultMap;
}
//子任务处理逻辑,子类中实现具体逻辑
public Object handle(Object input) {
return input;
}
@Override
public void run() {
while (true) {
//获取子任务
Object input = workQueue.poll();
if (input == null) {
break;
}
//处理子任务
Object re = handle(input);
//处理结果写入结果集
resultMap.put(Integer.toString(input.hashCode()), re);
}
}
}
public class Master {
//任务队列
protected Queue<Object> workQueue = new ConcurrentLinkedQueue<>();
//worker进程队列
protected Map<String, Thread> threadMap = new HashMap<>();
//子任务处理结果集,此处必须用ConcurrentHashMap,否则多线程put必然存在线程不安全问题,造成size值与实际数据量不符合。
protected Map<String, Object> resultMap = new ConcurrentHashMap<>();
//所有子任务结束
public boolean isComplete(){
for (Map.Entry<String, Thread> stringThreadEntry : threadMap.entrySet()) {
if(stringThreadEntry.getValue().getState() != Thread.State.TERMINATED){
return false;
}
}
return true;
}
//Master的构造,需要一个Worker进程逻辑,需要Worker进程数
public Master(Worker worker, int countWroker){
worker.setResultMap(resultMap);
worker.setWorkQueue(workQueue);
for (int i = 0; i < countWroker; i++) {
threadMap.put(Integer.toString(i), new Thread(worker, Integer.toString(i)));
}
}
//提交一个任务
public void submit(Object obj){
workQueue.add(obj);
}
//返回子任务结果集
public Map<String, Object> getResultMap(){
return resultMap;
}
//运行所有worker进程,进行处理
public void execute(){
for (Map.Entry<String, Thread> stringThreadEntry : threadMap.entrySet()) {
stringThreadEntry.getValue().start();
}
}
}
public class PlusWorker extends Worker {
@Override
public Object handle(Object input){
Integer i = (Integer) input;
return i*i*i;
}
}
public class MainTest {
public static void main(String[] args) {
Master m = new Master(new PlusWorker(), 5);
for (int i = 0; i < 100; i++) {
m.submit(i);
}
m.execute();
int re = 0;
Map<String, Object> resultMap = m.getResultMap();
while (resultMap.size() > 0 || !m.isComplete()){
Set<String> keys = resultMap.keySet();
String key = null;
for (String s : keys) {
key = s;
break;
}
Integer i = null;
if(key != null){
i = (Integer)resultMap.get(key);
}
if(i!= null){
re+=i;
}
if(key != null){
resultMap.remove(key);
}
}
System.out.println(re);
}
}
保护暂停模式,当服务进程准备好时候才提供服务。如下场景,服务器吞吐量有限的情况下,客户端不断的请求,可能会超时丢失请求,次数,我们将客户端请求进入队列,服务端一个一个处理。如下工作流图:
ResquestQueue队列用来缓存请求,使这种模式可以确保系统仅在有能力处理任务时候才获取队列这任务执行其他时间则等待。类似MQ提供的生产者消费者模式。如上模式并没有返回值的获取,有一定缺陷,如下改进流程图:
public class PCData {
private final int intData;
public PCData(int d ){
intData = d;
}
public PCData(String d){
intData = Integer.valueOf(d);
}
public int getIntData() {
return intData;
}
@Override
public String toString() {
return "PCData{" +
"intData=" + intData +
'}';
}
}
//生产者
public class Producer implements Runnable {
private volatile boolean isRunning = true;
private BlockingQueue<PCData> queue;
private static AtomicInteger count = new AtomicInteger();
private static final int SLEEPTIME = 1000;
public Producer(BlockingQueue<PCData> blockingQueue) {
this.queue = blockingQueue;
}
@Override
public void run() {
PCData data = null;
Random r = new Random();
System.out.println("start producer id = " + Thread.currentThread().getName());
try {
while (isRunning) {
Thread.sleep(r.nextInt(SLEEPTIME));
data = new PCData(count.incrementAndGet());
System.out.println(data + "is put into queue");
if (!queue.offer(data, 2, TimeUnit.SECONDS)) {
System.out.println("failed to put data: "+ data);
}
}
} catch (Exception e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
public void stop(){
isRunning = false;
}
}
//消费者
public class Consumer implements Runnable {
private BlockingQueue<PCData> queue;
private static final int SLEEPTIME = 1000;
public Consumer(BlockingQueue<PCData> queue){
this.queue = queue;
}
@Override
public void run() {
System.out.println("start consumer id= "+ Thread.currentThread().getId());
Random r = new Random();
try{
PCData pcData = queue.take();
if(null != pcData){
int re = pcData.getIntData() * pcData.getIntData();
System.out.println(MessageFormat.format("{0} * {1} ={2}", pcData.getIntData(), pcData.getIntData(), re));
Thread.sleep(r.nextInt(SLEEPTIME));
}
}catch (Exception e){
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
//run
public static void main(String[] args) throws InterruptedException {
BlockingQueue<PCData> queue = new LinkedBlockingQueue<>(10);
Producer producer1 = new Producer(queue);
Producer producer2 = new Producer(queue);
Producer producer3 = new Producer(queue);
Consumer consumer1 = new Consumer(queue);
Consumer consumer2 = new Consumer(queue);
Consumer consumer3 = new Consumer(queue);
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(producer1);
executorService.execute(producer2);
executorService.execute(producer3);
executorService.execute(consumer1);
executorService.execute(consumer2);
executorService.execute(consumer3);
Thread.sleep(10*1000);
producer1.stop();
producer2.stop();
producer3.stop();
Thread.sleep(3000);
executorService.shutdown();
}
/**
* @author liaojiamin
* @Date:Created in 10:33 2020/4/15
*/
public class ThreadPool {
private static ThreadPool instance = null;
//空闲队列
private List<PThread> idleThreads;
//线程总数
private int threadCounter;
private boolean isShutDown = false;
private ThreadPool(){
this.idleThreads = new Vector<>(5);
threadCounter = 0;
}
public int getCreatedThreadsCount(){
return threadCounter;
}
//获取线程池实例
public synchronized static ThreadPool getInstance(){
if(instance == null){
instance = new ThreadPool();
}
return instance;
}
//结束池中所有线程
public synchronized void shutDown(){
isShutDown = true;
for (int i = 0; i < idleThreads.size(); i++) {
PThread idleThread = (PThread) idleThreads.get(i);
idleThread.shutDown();
}
}
//将线程放入池中
protected synchronized void repool(PThread repoolingThread){
if(!isShutDown){
idleThreads.add(repoolingThread);
}else {
repoolingThread.shutDown();
}
}
//执行任务
public synchronized void start(Runnable target){
PThread thread = null;
//有空闲闲置至今获取最后一个使用
if(idleThreads.size() > 0){
int lastIndex = idleThreads.size() - 1;
thread = (PThread) idleThreads.get(lastIndex);
idleThreads.remove(lastIndex);
thread.setTarget(target);
}else {
//没有空闲线程新增一个线程并使用
threadCounter ++ ;
thread = new PThread(target, "PThread #" + threadCounter, this);
thread.start();
}
}
}
public class PThread extends Thread {
//线程池
private ThreadPool threadPool;
//任务
private Runnable target;
private boolean isShutDown = false;
private boolean isIdle = false;
public PThread(Runnable target,String name, ThreadPool pool){
super(name);
this.threadPool = pool;
this.target = target;
}
public Runnable getTarget(){
return target;
}
public boolean isIdle(){
return isIdle;
}
@Override
public void run(){
//只有没有关闭,一直运行不结束线程
while (!isShutDown){
isIdle = false;
if(target != null){
//运行任务
target.run();
}
//结束,修改闲置状态
isIdle = true;
threadPool.repool(this);
synchronized (this){
try {
//等待新任务
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isIdle = false;
}
}
public synchronized void setTarget(Runnable newTarget){
target = newTarget;
//设置任务后,通知run方法,开始执行任务
notifyAll();
}
public synchronized void shutDown(){
isShutDown = true;
notifyAll();
}
}
public class MyThread implements Runnable{
protected String name;
public MyThread(){}
public MyThread(String name){
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(100);
System.out.println("run target targetname: "+ Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
ThreadPool.getInstance().start(new MyThread("testThreadPool" + Integer.toString(i)));
//new Thread(new MyThread("testThreadPool" + Integer.toString(i))).start();
}
}
}
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 1000; i++) {
executorService.execute(new MyThread("testJDKThreadPool" + Integer.toString(i)));
}
public static ExecutorService newFixedThreadPool(int nThreads)
public static ExecutorService newWorkStealingPool(int parallelism)
public static ExecutorService newSingleThreadExecutor()
public static ExecutorService newCachedThreadPool()
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
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>());
}
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
public class MyThread implements Runnable, Comparable<MyThread>{
private String name;
public MyThread(){}
public MyThread(String name){
this.name = name;
}
@Override
public int compareTo(MyThread o) {
int me = Integer.parseInt(this.name.split("_")[1]);
int other = Integer.parseInt(o.name.split("_")[1]);
if(me > other) {
return 1;
}else if(me < other) {
return -1;
}else {
return 0;
}
}
@Override
public void run() {
try {
Thread.sleep(100);
System.out.println(name + " ");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class MainTest {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(100,
200 , 0L, TimeUnit.SECONDS,
new PriorityBlockingQueue<Runnable>());
for (int i = 0; i < 1000; i++) {
executorService.execute(new MyThread("testThreadPoolExecutor3_" + Integer.toString((999-i))));
}
}
}
/**
testThreadPoolExecutor3_989
testThreadPoolExecutor3_998
testThreadPoolExecutor3_999
testThreadPoolExecutor3_997
testThreadPoolExecutor3_996
testThreadPoolExecutor3_995
testThreadPoolExecutor3_973
testThreadPoolExecutor3_936
testThreadPoolExecutor3_970
......
testThreadPoolExecutor3_1
testThreadPoolExecutor3_6
testThreadPoolExecutor3_8
testThreadPoolExecutor3_9
testThreadPoolExecutor3_5
testThreadPoolExecutor3_11
*/
Ncpu = cpu数量
Ucpu = 目标Cpu的使用率 0<= Ucpu <=1
W/C = 等待时间与计算时间的比率
//公式
Nthread = Ncpu * (1+W/C)
//方法
Runtimg.getRuntime().availableProcessors();
protected void beforeExecute(Thread t, Runnable r)
protected void afterExecute(Runnable r, Throwable t)
protected void terminated()
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
//运行前
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
//运行结束
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
public class MyThreadPoolExecutor extends ThreadPoolExecutor {
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
protected void beforeExecute(Thread t, Runnable r){
System.out.println("beforeExecute myThread name: "+ ((MyThread)r).getName() + "TID: " + t.getId());
}
@Override
protected void afterExecute(Runnable r, Throwable t){
System.out.println("afterExecute TID:" + Thread.currentThread().getId());
System.out.println("afterExecute PoolSize: "+ this.getPoolSize());
}
}
//CopyOnWriteArrayList源码
private E get(Object[] a, int index) {
return (E) a[index];
}
public E get(int index) {
return get(getArray(), index);
}
//Vector
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
如上源码对比来看CopyOnWriteArrayList的get()方法并没有任何锁操作,而对比Vector的get()是用了Synchronized,所有get操作之前必须取得对象锁才能进行。在高并发读的时候大量锁竞争非常消耗系统性能,我们可以得出,在读性能上,CopyOnWriteArrayList是更优的一种方式。
接下来看下两个的写入方式add的源码
//vector中add方法
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
//CopyOnWriteArrayList中add方法
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
//Collections包中的方法
public static <T> Set<T> synchronizedSet(Set<T> s)
public synchronized void method(){}
//等价如下
public void method(){
synchronized(this){
....
}
}
public synchronized static void method(){}
public RentrantLock(boolean fair)
abstract void lock();//获得锁,如果被占用则等待
public void lockInterruptibly() throws InterruptedException //获得锁但有限响应中断
public boolean tryLock()//尝试获得,成功返回true,否则false,改方法不等待立刻返回
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException //给定实际内尝试获取锁
public void unlock()//释放锁
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
/** Main lock guarding all access */
final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
/**初始化锁,对Condition进行赋值*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
//加入队列
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();//队列满 利用await阻塞添加
enqueue(e);
} finally {
lock.unlock();
}
}
//从队列中获取元素
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();//队列空,利用await阻塞获取
return dequeue();
} finally {
lock.unlock();
}
}
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
//参数一指定信号量准入大小,fair 指定是否公平获取信号量
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
//尝试获取一个准入许可,无法获取则等待,知道有线程释放或者中断
public void acquire() throws InterruptedException
//尝试获取一个许可,成功返回true,否则false,不会等待直接返回
public boolean tryAcquire()
//线程访问资源结束后,释放一个许可,使其他等待许可的线程可以进行资源访问
public void release()
public void set(T value);//将次现场局部变量的当前线程副本中的值设置为指定值
public void remove();//移除此线程局部变量当前线程的值
public T get();//返回次现场局部变量的氮气线程副本中的值
public class ThreadLocalDemo implements Runnable{
public static final ThreadLocal<Date> localvar = new ThreadLocal<>();
private long time;
public ThreadLocalDemo(long time){
this.time = time;
}
@Override
public void run() {
Date d = new Date(time);
for (int i = 0; i < 50000; i++) {
localvar.set(d);//将d的值设置到线程的局部变量中
if(localvar.get().getTime() != time){//判断线程中值是否变化,如果有则输出
System.out.println("id = " + time + " localvar "+localvar.get().getTime());
}
}
}
public static void main(String[] args) throws InterruptedException {
//每次给与不同的时间测试是否有时间变化
for (int i = 0; i < 1000; i++) {
ThreadLocalDemo threadLocalDemo = new ThreadLocalDemo(new Date().getTime());
new Thread(threadLocalDemo).start();
Thread.sleep(100);
}
}
}
public void set(T value) {
Thread t = Thread.currentThread();//获取当前线程
ThreadLocalMap map = getMap(t);//获取线程ThreadLocalMap对象,每个线程独有
if (map != null)
map.set(this, value);将value设置到map中,get方法也是从这里获取数据
else
createMap(t, value);
}
/** Lock held by take, poll, etc take操作需要持有takeLock*/
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc put操作必须持有putLock*/
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
//获取takeLock
final ReentrantLock takeLock = this.takeLock;
//不能有两个线程同时读数据
takeLock.lockInterruptibly();
try {
while (count.get() == 0) {//没有数据一直等
notEmpty.await();//等待put操作中的notEmpty.signal方法释放
}
x = dequeue();//获取第一个数据节点
c = count.getAndDecrement();//统计数据增加1 原子操作
if (c > 1)
notEmpty.signal();//如果取出元素后还有剩余元素则通知其他take操作
} finally {
takeLock.unlock();//释放锁
}
if (c == capacity)
signalNotFull();//通知put操作,已经有剩余空间
return x;
}
//put操作类似,不重复
boolean tryLock(long time, TimeUnit unit);//锁等待时间功能
public void lockInterruptibly();//支持锁中断
public boolean tryLock()//快速锁轮换
public class LockTest {
private static final int CREATE = 20000000;
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < CREATE; i++) {
createStringBuffer("Java", "Performance");
}
long bufferCost = System.currentTimeMillis() - start;
System.out.println("createStringBUffer: "+ bufferCost + "ms");
}
public static String createStringBuffer(String str1, String str2){
StringBuffer sb = new StringBuffer();
sb.append(str1);
sb.append(str2);
return sb.toString();
}
}
public final boolean get()
public final boolean compareAndSet(boolean expect, boolean update)
public boolean weakCompareAndSet(boolean expect, boolean update)
public final void set(boolean newValue)
public final void lazySet(boolean newValue)
public final boolean getAndSet(boolean newValue)
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);//unsafe方法操作系统底层命令的调用
}
public final int getAndSetInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);//获取当前值
} while(!this.compareAndSwapInt(var1, var2, var5, var4));//尝试设置var4 作为新值,如果失败则继续循环直到成功为止
return var5;
}
协程不被java语言原生支持,我们可以使用kilim框架通过较低成本开发引入协程。
协程没有锁,同步块等概念,不会有多线程程序的复杂度,但是与java其他框架不同的是,开发后期需要通过kilim框架提供的织入(weaver)工具,将协程控制代码块织入原始代码,已支持协程的正常工作。如下图
Task是协程的任务载体,execute方法用于执行任务代码,fiber对象保存和管理任务执行堆栈,以实现任务可以正常暂停和继续。Mailbox对象为协程间的通信载体,用于数据共享和信息交流。
Fiber用来维护Task执行堆栈,Kilim框架对线程进行分割,以支持更小的并行度,所以Kilim需要自己维护执行堆栈
Fiber主要成员如下:
上图所示,^ 符号 标识并且的医生,其中begin,down,end,up标识Fiber操作iStack=0/up可以解毒为:进行up操作后iStack=0
Kilim 框架中协程间的通讯和数据交换依靠Mailbox邮箱进行,就像管道,多个Task间共享,以生产者消费者作类比,生产者向Mailbox提交一个数据,消费者协程则想Mailbox中获取数据。
public class TestStack {
private static int count = 0;
public void recursion(){
count ++;
System.out.println("deep of stack :" + count);
recursion();
}
public static void main(String[] args) {
TestStack testStack = new TestStack();
try{
testStack.recursion();
}catch (Exception e){
System.out.println("deep of stack :" + count);
e.printStackTrace();
}
}
}
/**输出
1M栈输出
deep of stack :5544
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
......
2M栈输出
deep of stack :11887
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
**/
public class TestStack {
private static int count = 0;
public void recursion(long a, long b, long c){
long d=0,e=0,f=0;
count ++;
System.out.println("deep of stack :" + count);
recursion(1l,2l,3l);
}
public static void main(String[] args) {
TestStack testStack = new TestStack();
try{
testStack.recursion(1l,2l,3l);
}catch (Exception e){
System.out.println("deep of stack :" + count);
e.printStackTrace();
}
}
}
//-Xss1M 输出
deep of stack :4167
Exception in thread "main" java.lang.StackOverflowError
at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
如上可看出,调用函数参数,局部变量越多,占用栈内存越大,导致调用次数比无参数时候下降5544–>4167
可见最大局部变量是13,是这么算的,局部变量存放单位字32位(并非字节),long,double是64为,两个字,所以三个参数,三个局部变量都是long 6*2=12个字,还有一个非static方法,虚拟机回将当前对象(this)最为参数通过局部变量传递给当前方法所以最终13字
局部变量中的字对GC有一定影响,如果局部变量被保存在局部变量表,GC根能引用到这个局部变量所指向的空间,可达性算法判断不可回收,因此不会清除,如下:
public static void test1(){
{
byte[] b = new Byte[6*1224*1024];
}
System.gc();
System.out.println(""s)
}
//GC日志
[GC (System.gc()) [PSYoungGen: 10006K->512K(38400K)] 10006K->7856K(125952K), 0.0077538 secs]
[Times: user=0.01 sys=0.01, real=0.01 secs]
[Full GC (System.gc()) [PSYoungGen: 512K->0K(38400K)]
[ParOldGen: 7344K->7739K(87552K)] 7856K->7739K(125952K),
[Metaspace: 3117K->3117K(1056768K)], 0.0070191 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
the first byte
java堆运行是内存,几乎所有对象和数组都在堆空间分配内存,堆内存分为新生代存放刚产生对象和年轻对象,老年代,存放新生代中一定时间内一直没有被回收的对象。如下
如上图,新生代分为三个部分:
如下案例我用JVM参数:
-XX:+PrintGCDetails //打印GC日志
-XX:SurvivorRatio=8 //JVM参数中有一个比较重要的参数SurvivorRatio,它定义了新生代中Eden区域和Survivor区域(From幸存区或To幸存区)的比例,默认为8,也就是说Eden占新生代的8/10,From幸存区和To幸存区各占新生代的1/10
-XX:MaxTenuringThreshold=15 //设置对象进入老年代需要的GC次数
-Xms20M // jjvm最小可用内存
-Xmx20M //jvm最大可用内存
-Xmn12M //年轻代大小设置
public class TestHeapGC {
public static void main(String[] args) {
byte[] b1 = new byte[1024*1024/2]; //0.5M
byte[] b2 = new byte[1024*1024*8]; //8M
b2 = null;
b2 = new byte[1024*1024*8]; //8M
// System.gc();
}
}
//GC日志
Heap
PSYoungGen total 11264K, used 9066K [0x00000007bf400000, 0x00000007c0000000, 0x00000007c0000000)
eden space 10240K, 84% used [0x00000007bf400000,0x00000007bfc66868,0x00000007bfe00000)
from space 1024K, 45% used [0x00000007bff00000,0x00000007bff74010,0x00000007c0000000)
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
ParOldGen total 8192K, used 1032K [0x00000007bec00000, 0x00000007bf400000, 0x00000007bf400000)
object space 8192K, 12% used [0x00000007bec00000,0x00000007bed02010,0x00000007bf400000)
Metaspace used 3134K, capacity 4494K, committed 4864K, reserved 1056768K
class space used 349K, capacity 386K, committed 512K, reserved 1048576K
Heap
PSYoungGen total 11264K, used 8744K [0x00000007bf400000, 0x00000007c0000000, 0x00000007c0000000)
eden space 10240K, 85% used [0x00000007bf400000,0x00000007bfc8a190,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
ParOldGen total 8192K, used 1025K [0x00000007bec00000, 0x00000007bf400000, 0x00000007bf400000)
object space 8192K, 12% used [0x00000007bec00000,0x00000007bed00658,0x00000007bf400000)
Metaspace used 3175K, capacity 4494K, committed 4864K, reserved 1056768K
class space used 352K, capacity 386K, committed 512K, reserved 1048576K
//jvm参数:-XX:PermSize=1M -XX:MaxPermSize=2m -XX:+PrintGCDetails
public class TestGCPermGen {
public static void main(String[] args) {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
String t = String.valueOf(i).intern();
}
}
}
//GC日志
.....
[GC (Allocation Failure) [PSYoungGen: 133568K->464K(138240K)] 133584K->480K(225792K), 0.1607520 secs] [Times: user=0.16 sys=0.00, real=0.16 secs]
[GC (Allocation Failure) [PSYoungGen: 133584K->448K(266752K)] 133600K->464K(354304K), 0.2681573 secs] [Times: user=0.26 sys=0.00, real=0.27 secs]
[GC (Allocation Failure) [PSYoungGen: 266688K->0K(266752K)] 266704K->428K(354304K), 0.4384817 secs] [Times: user=0.43 sys=0.01, real=0.44 secs]
....
//jvm参数:-XX:PermSize=1M -XX:MaxPermSize=2m -XX:+PrintGCDetails
public class JavaBeanObject {
private String name = "java";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class JavaBeanGCTest {
public static void main(String[] args) throws Exception{
for (int i = 0; i < Integer.MAX_VALUE; i++) {
CtClass cc = ClassPool.getDefault().makeClass("Geym" + i);
cc.setSuperclass(ClassPool.getDefault().get("com.ljm.jvm.JavaBeanObject"));
Class clz = cc.toClass();
JavaBeanObject v = (JavaBeanObject) clz.newInstance();
}
}
}
GC日志:
......
[GC (Allocation Failure) [PSYoungGen: 832K->320K(1024K)] 2970K->2738K(3584K), 0.0010876 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 320K->0K(1024K)] [ParOldGen: 2418K->2058K(2560K)] 2738K->2058K(3584K), [Metaspace: 5480K->5480K(1056768K)], 0.0193576 secs] [Times: user=0.05 sys=0.00, real=0.02 secs]
[GC (Allocation Failure) [PSYoungGen: 512K->320K(1024K)] 2570K->2386K(3584K), 0.0004815 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 832K->352K(1024K)] 2898K->2690K(3584K), 0.0007751 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (Ergonomics) [PSYoungGen: 352K->0K(1024K)] [ParOldGen: 2338K->2556K(2560K)] 2690K->2556K(3584K), [Metaspace: 5757K->5757K(1056768K)], 0.0174732 secs] [Times: user=0.04 sys=0.01, real=0.01 secs]
......
//参数:-XX:+PrintGCDetails -Xms1M -Xmx11M
public class GCTimesTest {
public static void main(String[] args) {
Vector vector = new Vector();
for (int i = 0; i < 20; i++) {
byte[] bytes = new byte[1024*1024];
vector.add(bytes);
if(vector.size() > 3){
vector.clear();
}
}
}
}
//GC日志
......
[GC (Allocation Failure) [PSYoungGen: 506K->400K(1024K)] 506K->408K(1536K), 0.0008198 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 805K->480K(1024K)] 7981K->7664K(9216K), 0.0010682 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
[GC (Allocation Failure) [PSYoungGen: 480K->496K(1024K)] 7664K->7680K(9216K), 0.0005386 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 496K->0K(1024K)] [ParOldGen: 7184K->1424K(3072K)] 7680K->1424K(4096K), [Metaspace: 3117K->3117K(1056768K)], 0.0063393 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 10K->96K(1536K)] 7579K->7664K(9728K), 0.0005220 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 96K->128K(1536K)] 7664K->7696K(9728K), 0.0003231 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (Allocation Failure) [PSYoungGen: 128K->0K(1536K)] [ParOldGen: 7568K->1411K(3584K)] 7696K->1411K(5120K), [Metaspace: 3169K->3169K(1056768K)], 0.0046456 secs] [Times: user=0.00 sys=0.01, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 31K->96K(3072K)] 7586K->7651K(11264K), 0.0003348 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
......
-XX:+PrintGCDetails -Xms1M -Xmx11M
-XX:+PrintGCDetails -Xms11M -Xmx11M -Xmn2M
public class JavaBeanGCTest {
public static void main(String[] args) throws Exception{
Integer count = 0;
try {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
CtClass cc = ClassPool.getDefault().makeClass("Geym" + i);
cc.setSuperclass(ClassPool.getDefault().get("com.ljm.jvm.JavaBeanObject"));
Class clz = cc.toClass();
JavaBeanObject v = (JavaBeanObject) clz.newInstance();
count++;
}
}catch (Exception e){
System.out.println("test test---------------------"+ count);
}
}
}
//JVM参数:-XX:PermSize=1M -XX:MaxPermSize=2m -XX:+PrintGCDetails
//JVM参数:-XX:PermSize=2M -XX:MaxPermSize=4m -XX:+PrintGCDetails
public class StackTest {
public static class MyThread extends Thread{
@Override
public void run(){
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
int i=0;
try {
for (i = 0; i < 1000000; i++) {
new MyThread().start();
}
}catch (Exception e){
System.out.println("count thread is " + i);
}
}
}
//JVM参数-Xss1M
//JVM参数用-XX:+PrintGCDetails -Xmn10M -XX:SurvivorRatio=8测试:
PSYoungGen total 9216K, used 2516K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 8192K, 30% used [0x00000000ff600000,0x00000000ff875110,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
to space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
ParOldGen total 118784K, used 0K [0x0000000082200000, 0x0000000089600000, 0x00000000ff600000)
object space 118784K, 0% used [0x0000000082200000,0x0000000082200000,0x0000000089600000)
Metaspace used 3435K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 374K, capacity 388K, committed 512K, reserved 1048576K
我们使用参数 -XX:+PrintGCDetails -Xmn10M -XX:SurvivorRatio=2
Heap
PSYoungGen total 7680K, used 2327K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
eden space 5120K, 45% used [0x00000000ff600000,0x00000000ff845c60,0x00000000ffb00000)
from space 2560K, 0% used [0x00000000ffd80000,0x00000000ffd80000,0x0000000100000000)
to space 2560K, 0% used [0x00000000ffb00000,0x00000000ffb00000,0x00000000ffd80000)
ParOldGen total 118784K, used 0K [0x0000000082200000, 0x0000000089600000, 0x00000000ff600000)
object space 118784K, 0% used [0x0000000082200000,0x0000000082200000,0x0000000089600000)
Metaspace used 3445K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 376K, capacity 388K, committed 512K, reserved 1048576K
//Jvm参数设置:-XX:+PrintGCDetails -Xmn10M -XX:SurvivorRatio=2 -XX:NewRatio=2 -Xmx20M -Xms20M
PSYoungGen total 6144K, used 2350K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)
eden space 5632K, 41% used [0x00000000ff980000,0x00000000ffbcba40,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
ParOldGen total 13824K, used 0K [0x00000000fec00000, 0x00000000ff980000, 0x00000000ff980000)
object space 13824K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff980000)
Metaspace used 3454K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 377K, capacity 388K, committed 512K, reserved 1048576K
基于标记算法将原内存分两块,每次用其中一块,GC时候,将存活对象复制到另一块内存中,清楚原来内存块中所有对象,然后交换角色。
优势:如果系统中垃圾对象多,复制算法需要复制的就少,此时复制算法效率最高,并且统一复制到某一块内存,不会有内存碎片。
用处: Java新生代串行垃圾回收器使用复制算法,Eden空间,from,to空间三部分,from = to空间,天生就有区域划分,并且from与to空间角色互换。因此GC时候,eden空间存活对象复制到survivor空间(假设是to),正在使用的survivor(from)中的年前对象复制到to,大对象to放不下直接进入old区域,to满了,其他放不下的直接去old区域,之后清理eden与from去。
分类 | 垃圾回收器类型 |
---|---|
线程数 | 串行垃圾回收器 |
线程数 | 并行垃圾回收器 |
工作模式 | 并发垃圾回收器 |
工作模式 | 独占垃圾回收器 |
碎片处理 | 压缩垃圾回收器 |
碎片处理 | 非压缩垃圾回收器 |
分代 | 新生代垃圾回收器 |
分代 | 老年代圾回收器 |
Concurrent Mark Sweep,并发标记清除,标记清除算法,同时也是多线程并行回收的垃圾收集器回收过程如下:
JVM参数介绍,CMS执行期间有部分并行执行,对吞吐量影响是不可避免的,
link G1资源
G1是JDK1.6出试用,1.7 后才开始正式,java1.9的默认收集器,用于替代CMSDE新型GC,解决CMS空间碎片等一系列缺陷,是适用于java HotSpotVM的低暂停,服务器风格的分带式垃圾回收器。
要了解G1的GC原理,先要知道G1的一些设计理论。
YoungGC的时候,Young区域(年轻代)对象还可能存在Old区的引用,这是夸代引用,此时如果年轻代GC触发,为避免扫描整个老年代,G1 引入了两个概念Card Table和Remember Set。思路是空间换时间,用来记录Old到Young区的引用。
如上图,RSet与Card,每个Region多个Card,绿色部分Card表示这个card中有对象引用了其他card中对象,Rset是一个HashTable,key是Region的起始地址,value是catdTable类似Map
SATB全称(Snapshot At the Beginning)GC钱存活对象的快照。作用是保证并发标记阶段的正确性。理解整个我们需要先知道三色标记算法,如下图:
黑色:根对象,或者该对象与它的子对象都被扫描过
灰色:对象本身被扫描,单没有扫描他的子对象
白色:未被扫描对象,扫描完成所有对象后,最终为白色的是不可达对象即垃圾对象
如下案例GC扫码C之前颜色如下:
A.c = C
B.c = null
![Java调优-G1三色标记算法案例图二](WEBRESOURCE5d1f2cf47cb27a3e944c10e2b11e7d67)
这种情况C会被清理,因为在第二阶段A已被标记黑色,说明A及其子类已经被扫描过,之后不会再重复扫描。此时Snapshot存活对象原来是A,B,C,现在是A,B。快照被破坏显然不合理。
解决凡是:G1 采用pre-write barrier解决,在并发标记阶段引用关系变化的记录都通过pre-write barrier存储在一个队列,JVM源码中这个队列叫satb_mark_queue。在remark阶段(重新标记阶段)会扫描这个队列,通过这种凡是旧的引用指向对象也会被标记,其子孙类递归标记上,不会漏任何对象,以此保证snapshot完整性。
此部分也是G1 相对CMS的一个优势,在remark阶段是独占的,CMS中incremental update设计使得它在remark阶段必须重新扫描所有线程栈和整个young gen作为root,但是G1 的SATB设计在remark阶段只需要扫描队剩下的satb_mark_queue,解决CMS的GC重新标记阶段长时间STW的潜在风险。
弊端: Satb方式记录存活对象,当snapshot时刻,可能之后这个对象就变成了垃圾,这个叫浮动垃圾(floating garbage),这种只能下次GC回收,这次GC过程中性分配的对象是活的,其他不可达对象就是死的。
接着又有问题:下次GC如何区分哪些对象是GC开始后重新分配,哪些是浮动垃圾
如上Region中指针设计,top是region当前指针
通过以上几个区域划分可以得出每次GC应该清理的上次留下来的隐式存活对象并且进行清理。
//JVM参数控制启用G1回收器
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
-XX:MaxGCPauseMillis =50
-XX:GCPauseIntervalMillis = 200
public class StopTheWorldTest {
public static class MyThread extends Thread{
Map<Long, Object> map = new HashMap<>();
@Override
public void run(){
try {
while(true) {
if (map.size() * 512 / 1204 / 1024 >= 400) {//防止OOM
map.clear();
System.out.println("clean map");
}
byte[] b;
for (int i = 0; i < 100; i++) {
b = new byte[512];
map.put(System.nanoTime(), b);
}
}
}catch (Exception e){
}
}
}
public static class PrintThread extends Thread{
public static final long startTime = System.currentTimeMillis();
@Override
public void run(){
try{
while (true){
Long t = System.currentTimeMillis() -startTime;
System.out.println(t/1000+" . "+ t%1000);
Thread.sleep(100);
}
}catch (Exception e){
}
}
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
PrintThread p =new PrintThread();
myThread.start();
p.start();
}
}
//JVM参数
-Xmx512M -Xms512M -XX:+UseSerialGC -Xloggc:gc.log -XX:+PrintGCDetails
//输出
......
1 . 977
2 . 715
[Full GC (Allocation Failure) [Tenured: 349567K->349567K(349568K), 0.3569460 secs] 506815K->506815K(506816K), [Metaspace: 3234K->3234K(1056768K)], 0.3569830 secs] [Times: user=0.35 sys=0.00, real=0.36 secs]
3 . 777
[Full GC (Allocation Failure) [Tenured: 349567K->349567K(349568K), 0.3663700 secs] 506815K->506815K(506816K), [Metaspace: 3238K->3238K(1056768K)], 0.3664147 secs] [Times: user=0.36 sys=0.00, real=0.36 secs]
[Full GC (Allocation Failure) [Tenured: 349568K->349568K(349568K), 0.4278699 secs] 506816K->506815K(506816K), [Metaspace: 3239K->3239K(1056768K)], 0.4279018 secs] [Times: user=0.42 sys=0.01, real=0.43 secs]
4 . 144
[Full GC (Allocation Failure) [Tenured: 349568K->349568K(349568K), 0.4185880 secs] 506815K->506815K(506816K), [Metaspace: 3240K->3240K(1056768K)], 0.4186427 secs] [Times: user=0.42 sys=0.00, real=0.42 secs]
[Full GC (Allocation Failure) [Tenured: 349568K->349568K(349568K), 0.4118220 secs] 506815K->506815K(506816K), [Metaspace: 3240K->3240K(1056768K)], 0.4118646 secs] [Times: user=0.40 sys=0.00, real=0.41 secs]
[Full GC (Allocation Failure) [Tenured: 349568K->349567K(349568K), 0.4089358 secs] 506815K->506815K(506816K), [Metaspace: 3240K->3240K(1056768K)], 0.4089639 secs] [Times: user=0.41 sys=0.00, real=0.41 secs]
.....
public class GCTimeTest {
static HashMap map = new HashMap();
public static void main(String[] args) {
long beginTime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
if (map.size() * 512 / 1024 / 1024 >= 400) {
map.clear();
System.out.print("clean up");
}
byte[] b1;
for (int j = 0; j < 100; j++) {
b1 = new byte[512];
map.put(System.nanoTime(), b1);
}
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - beginTime);
}
}
回收器 | 耗时ms |
---|---|
-Xmx512M -Xms512M -XX:+UseParNewGC | 1326 |
-Xmx512M -Xms512M -XX:+UseParallelOldGC -XX:ParallelGCThreads=8 | 1565 |
-Xmx512M -Xms512M -XX:+UseSerialGC | 1530 |
-Xmx512M -Xms512M -XX:+UseConcMarkSweepGC | 1687 |
public class PutInEden {
public static void main(String[] args) {
byte[] b1,b2,b3,b4,b5;//5M内存分配
b1 = new byte[1024*1024];
b2 = new byte[1024*1024];
b3 = new byte[1024*1024];
b4 = new byte[1024*1024];
b5 = new byte[1024*1024];
}
}
PSYoungGen total 6144K, used 1633K [0x00000007bf980000, 0x00000007c0000000, 0x00000007c0000000)
eden space 5632K, 20% used [0x00000007bf980000,0x00000007bfa9c470,0x00000007bff00000)
from space 512K, 96% used [0x00000007bff00000,0x00000007bff7c010,0x00000007bff80000)
to space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
ParOldGen total 13824K, used 4104K [0x00000007bec00000, 0x00000007bf980000, 0x00000007bf980000)
object space 13824K, 29% used [0x00000007bec00000,0x00000007bf002040,0x00000007bf980000)
Metaspace used 3103K, capacity 4494K, committed 4864K, reserved 1056768K
class space used 343K, capacity 386K, committed 512K, reserved 1048576K
PSYoungGen total 8192K, used 6463K [0x00000007bf700000, 0x00000007c0000000, 0x00000007c0000000)
eden space 7168K, 90% used [0x00000007bf700000,0x00000007bfd4ff00,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
ParOldGen total 11264K, used 0K [0x00000007bec00000, 0x00000007bf700000, 0x00000007bf700000)
object space 11264K, 0% used [0x00000007bec00000,0x00000007bec00000,0x00000007bf700000)
Metaspace used 3102K, capacity 4494K, committed 4864K, reserved 1056768K
class space used 343K, capacity 386K, committed 512K, reserved 1048576K
public class PutInEden {
public static void main(String[] args) {
byte[] b1,b2,b3,b4,b5;
b1 = new byte[1024*512];
b2 = new byte[1024*1024*4];
b3 = new byte[1024*1024*4];
b3=null;
b3 = new byte[1024*1024*4];
}
}
PSYoungGen total 9216K, used 6123K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 8192K, 74% used [0x00000007bf600000,0x00000007bfbfae40,0x00000007bfe00000)
from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)
to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000)
ParOldGen total 10240K, used 8192K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
object space 10240K, 80% used [0x00000007bec00000,0x00000007bf400020,0x00000007bf600000)
Metaspace used 3178K, capacity 4494K, committed 4864K, reserved 1056768K
class space used 353K, capacity 386K, committed 512K, reserved 1048576K
PSYoungGen total 7680K, used 5274K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
eden space 5120K, 83% used [0x00000007bf600000,0x00000007bfa26858,0x00000007bfb00000)
from space 2560K, 40% used [0x00000007bfb00000,0x00000007bfc00010,0x00000007bfd80000)
to space 2560K, 0% used [0x00000007bfd80000,0x00000007bfd80000,0x00000007c0000000)
ParOldGen total 10240K, used 8200K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
object space 10240K, 80% used [0x00000007bec00000,0x00000007bf402020,0x00000007bf600000)
Metaspace used 3178K, capacity 4494K, committed 4864K, reserved 1056768K
class space used 353K, capacity 386K, committed 512K, reserved 1048576K
java -Xmx3800M -Xms3800 -Xmn2G
-Xss128k //减少线程栈大小可以支持更多线程
-XX:+UseParallelGC //年轻代用并行回收收集器
-XX:ParallelGCThreads=20 //设置用于GC线程的数量
-XX:+UseParallelOldGC //老年代使用并行回收收集器
java -Xms2506M -Xmx2506M -Xmn1536M -Xss128k
-XX:ParallelGCThread=20 //并行回收收集线程20个
-XX:+UseConcMarkSweepGC //老年代使用CMS收集器
-XX:+UseParNewGC //年轻代使用并行回收器
-XX:SurvivorRatio=8 //年轻代eden:from=8:1
-XX:TargetSurvivorRatio=90 //设置survivor可食用的百分比90%,默认50%超过则进入老年代
-XX::MaxTenuringThreshold=31 //晋升老年代年龄31次GC,默认15
//JVM参数:-XX:+PrintGCDetails -Xmx5M -Xms5M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/jiamin
public class PutInEden {
public static void main(String[] args) throws InterruptedException {
Map<Object,Object> map = new HashMap<>();
byte[] b1;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
b1 = new byte[100];
map.put(System.nanoTime(), b1);
Thread.sleep(100);
}
}
}
分配4M堆,指定dump文件目录,每一毫秒分配100B内存观察堆内存占用,GC次数一次每次GC时候堆内存变化,线程数量等新能指标,
以上堆空间循环上升按规律下降可以看出每一毫秒分配一个byte对象,并且加入map中,一定时间后回触发GC应为堆内存只有4M,也可手动执行GC,查看线程,当前内存信息,CPU信息呢,可从一下入口:
可以dump出当前堆快照查看当前时刻各个性能指标等功能。自动生成Dump文件,同样左边控制台上查看,并且支持OQL查询功能
select <javascript expression to select>
[
from [instanceof] <class name> <identifier>
[where <javaScript boolean expression to filter>]
]
select s from byte[] s where s.length>=10
select {instance:s, content:s.toString()} from java.lang.String s where /^\d{2}$/(s.toString))
select {content:file.path.toString(), instance:file} from java.io.File file
select c1 from instanceof java.lang.ClassLoader c1
//查找demo中指定名称对应的类
select heap.findClass("com.ljm.jvm.PutInEden").superclasses()
//查找IO包下的对象
select filter(heap.classes(), "java.io")
select classof(v) from instanceof java.util.Vector v
select objectid(v) from java.util.Vector v
reachables(obj,[filter])
//返回56 这个String对象的所有可达对象
select reachables(s) from java.lang.String s
where s.toString == '56'
//返回FIle对象的静态成员变量引用
select referees(heap.findClass("java.io.File"))
//返回所有byte数组的大小以及对象
select {size:sizeof(o), Object:o} from byte[] o
select {size:sizeof(o), rsize:rsizeof(o)}
from java.util.Vector o
//返回被File对象引用的String对象的集合,先通过referrers得到所有引用String对象的对象集合,使用contains函数以及布尔等式将contains的筛选条件设置为类名是java.io.File的对象
select s.toString() from java.lang.String s where
contains(referrers(s), "classof(it).name == 'java.io.File'")
select count(heap.classes(),"java.io")
JAVA_OPTS=" -Xloggc:/Users/jiamin/work_soft/tomcat7.0/apache-tomcat-7.0.77/gc.$$.log"
JAVA_OPTS="-Xms32m -Xmx32m -Xloggc:/Users/jiamin/work_soft/tomcat7.0/apache-tomcat-7.0.77/gc.$$.log -XX:+DisableExplicitGC"
CommandLine flags: -XX:+DisableExplicitGC -XX:InitialHeapSize=33554432 -XX:MaxHeapSize=33554432 -XX:MaxNewSize=16777216 -XX:NewSize=16777216 -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
0.449: [GC (Allocation Failure) 12288K->3206K(30720K), 0.0054239 secs]
0.730: [GC (Allocation Failure) 15494K->5902K(30720K), 0.0059441 secs]
0.931: [GC (Allocation Failure) 18190K->8205K(30720K), 0.0049580 secs]
1.086: [GC (Allocation Failure) 20493K->10396K(30720K), 0.0067136 secs]
1.215: [GC (Allocation Failure) 22684K->12239K(30720K), 0.0054546 secs]
1.332: [GC (Allocation Failure) 24527K->14135K(24576K), 0.0048293 secs]
1.405: [GC (Allocation Failure) 20279K->15202K(27648K), 0.0049688 secs]
1.462: [GC (Allocation Failure) 21346K->15679K(27648K), 0.0027720 secs]
1.465: [Full GC (Ergonomics) 15679K->13990K(27648K), 0.0583449 secs]
141.964: [Full GC (Ergonomics) 20134K->9003K(27648K), 0.0463495 secs]
JAVA_OPTS="-Xms32m -Xmx32m -Xloggc:/Users/jiamin/work_soft/tomcat7.0/apache-tomcat-7.0.77/gc.$$.log -XX:+DisableExplicitGC -XX:NewRatio=2"
CommandLine flags: -XX:+DisableExplicitGC -XX:InitialHeapSize=33554432 -XX:MaxHeapSize=33554432 -XX:NewRatio=2 -XX:+PrintGC -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
0.311: [GC (Allocation Failure) 8704K->2424K(31744K), 0.0041321 secs]
0.617: [GC (Allocation Failure) 11128K->4419K(31744K), 0.0042971 secs]
0.835: [GC (Allocation Failure) 13123K->6160K(31744K), 0.0060738 secs]
0.983: [GC (Allocation Failure) 14864K->8129K(31744K), 0.0051707 secs]
1.072: [GC (Allocation Failure) 16833K->9418K(31744K), 0.0044853 secs]
1.193: [GC (Allocation Failure) 18122K->11046K(26624K), 0.0066215 secs]
1.238: [GC (Allocation Failure) 14630K->12013K(29184K), 0.0043997 secs]
1.298: [GC (Allocation Failure) 15597K->12212K(29184K), 0.0023517 secs]
1.334: [GC (Allocation Failure) 15794K->12356K(29184K), 0.0025246 secs]
1.356: [GC (Allocation Failure) 15940K->12762K(29184K), 0.0029685 secs]
1.390: [GC (Allocation Failure) 16346K->12849K(29184K), 0.0024812 secs]
1.453: [GC (Allocation Failure) 16433K->13049K(29184K), 0.0011466 secs]
1.512: [GC (Allocation Failure) 16633K->13312K(29184K), 0.0010865 secs]
1.531: [GC (Allocation Failure) 16896K->13693K(29184K), 0.0011136 secs]
1.557: [GC (Allocation Failure) 17277K->13926K(29184K), 0.0012882 secs]
1.578: [GC (Allocation Failure) 17510K->14371K(29184K), 0.0012781 secs]
JAVA_OPTS="-Xms32m -Xmx32m -Xloggc:/Users/jiamin/work_soft/tomcat7.0/apache-tomcat-7.0.77/gc.$$.log -XX:+DisableExplicitGC -XX:NewRatio=2 -XX:+UseParallelGC"
第一次:
JAVA_OPTS="-Xms512m -Xmx512m -XX:PermSize=32M -XX:MaxPermSize=32M -XX:+DisableExplicitGC"
第二次:
JAVA_OPTS="-Xms512m -Xmx512m -XX:PermSize=32M -XX:MaxPermSize=32M -XX:+PrintGCDetails -XVerify:none -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:ParallelGcThreads=8 -XX:+DisableExplicitGC"
第三次:
JAVA_OPTS="-Xms512m -Xmx512m -XX:PermSize=32M -XX:MaxPermSize=32M -XX:+PrintGCDetails -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:ParallelCMSTHreads=8, -XX:+UseCMSCOmpactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0(设定进行多少次CMS垃圾回收后,进行一次内存压缩)
-XX:CMSInitiatingOccupancFraction=78
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+CMSParallelRemarkEnabled
-XX:SurvivorRatio=1
-XX:+UseParNewGC"
sar [options] [<interval> [count]]
interval:采样周期 和 count:采样数量。option选项可以指定sar命令对那些性能数据进行采样
获取内存使用情况 sar -r 1 5
获取IO信息 sar -b 1 5
vmstat也是一个功能齐全的性能检测工具,统计CPU,内存使用情况,swap使用情况等信息,同样周期采样,格式雷同
vmstat 1 5 没秒一次共五次
输出中各项意义:
总结:vmstat工具可以查看内存,交互分区,IO操作,上下文切换,时钟中断以及CPU的使用情况
以上命令每秒采样一次持续五次,展示了CPU使用和磁盘IO的信息,如果只需要磁盘IO信息iostat -d 1 5
-d标识输出磁盘使用情况,结果各参数含义如下:
iostat可以快速定位系统是否产生了大量IO操作‘
public class HoldCPUMain {
public static class HoldCpuTesk implements Runnable{
@Override
public void run() {
while (true){
double a = Math.random()* Math.random();
}
}
}
public static class LazyTask implements Runnable{
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new Thread(new HoldCpuTesk()).start();
new Thread(new LazyTask()).start();
new Thread(new LazyTask()).start();
new Thread(new LazyTask()).start();
}
}
以上demo中跑四个线程,其中一个占用CPU资源,其他空闲,先使用jps找出java程序的PID, 接着使用pidstat命令输出程序CPU使用情况, pidstat -p 1187 -u 1 3
如上图所示,我们先用jps找到Java程序的PID,然后pidstat命令输出CPU使用情况
pidstat参数 -p 用来指定进程ID,-u指定值需要CPU的信息,最后1,3表示每秒一次,打印三次,从输出看出,CPU占用最后能达到100%,idstat功能还可以监控线程信息,如下命令:
pidstat -p 1187 1 3 -u -t
![java调优-java性能优化工具pidstat](WEBRESOURCE6884842dda92c20ccfee5e9532d60b46)
jstack -l 1187 >/temp/thread.txt
![java调优-java性能优化工具jstack](WEBRESOURCE382f0f722bba8c4f202446eff47626c1)
磁盘也是常见性能瓶颈之一,pidstat也可以监控IO情况,如下排查流程:
top命令查看基础系统资源信息如下,可以看到如下图中PID=10580 的java进程占用VIRT(虚拟内存)%CPU(上次结束CPU占比)都居于第一,资源消耗厉害,
获取到pid后,用如下命令获取对应详细线程信息,如下图所示
pidstat -p 10580 -d -t 1 3
![java调优-java性能优化pidstat线程](WEBRESOURCEdd5b0ec89480929a899344d6bfe12435)
pidstat -r -p 10580 1 5
jiamindeMacBook-Pro:~ jiamin5$ jps
75712 AppMain
75664 RemoteMavenServer
75737 Jps
75711 Launcher
75454
jstat -<option> [-t] [-h<lines>] <vmid> [<interval>] [<coune>]
jstat -gccapacity -t 78305 1000 2 //显示各个代的容量以及使用情况,
jstat -class -t 78305 1000 2 //每一秒统一一次类加载信息,总共统计两次
jstat -gc -t 80800 1000 100 //打印堆内存各个区域使用情况,GC情况,如下输出:
Timestamp S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
89.9 512.0 512.0 0.0 496.0 1024.0 892.5 4096.0 40.0 4864.0 3194.5 512.0 353.9 1 0.001 0 0.000 0.001
90.9 512.0 512.0 0.0 496.0 1024.0 892.5 4096.0 40.0 4864.0 3194.5 512.0 353.9 1 0.001 0 0.000 0.001
91.9 512.0 512.0 0.0 496.0 1024.0 913.1 4096.0 40.0 4864.0 3194.5 512.0 353.9 1 0.001 0 0.000 0.001
jinfo <option> <pid>
jhat dump.hprof
jiamindeMacBook-Pro:~ jiamin5$ jhat dump.hprof
Reading from dump.hprof...
Dump file created Thu May 07 22:06:52 CST 2020
Snapshot read, resolving...
Resolving 13100 objects...
Chasing references, expect 2 dots..
Eliminating duplicate references..
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
jstack -l 83183 > /Users/jiamin/deadlock.txt
//死锁输出如下
Found one Java-level deadlock
。。。。。。
之前都是本机java程序的监控,jstatd是远程监控,jstatd是一个RMI服务员端程序,相当于一个代理服务器,建立本地与被监控计算机的监控工具的通信,jstatd服务器将本机的java引用程序信息传递到远程计算机如下图:
测试demo如下
public class HoldCPUMain {
public static class HoldCpuTesk implements Runnable{
@Override
public void run() {
while (true){
double a = Math.random()* Math.random();
}
}
}
public static class LazyTask implements Runnable{
@Override
public void run() {
while (true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new Thread(new HoldCpuTesk()).start();
new Thread(new LazyTask()).start();
new Thread(new LazyTask()).start();
new Thread(new LazyTask()).start();
}
}
jconsole -pluginpath %JAVA_HOME%/demo/management/JTop/JTop.jar
public class Point {
private int x;
private int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
}
public class Line {
private Point startPoint;
private Point endPoint;
public Line(Point startPoint, Point endPoint){
this.startPoint = startPoint;
this.endPoint = endPoint;
}
public static void main(String[] args) {
Point a = new Point(0,0);
Point b = new Point(0,0);
Point c = new Point(0,0);
Point d = new Point(0,0);
Point e = new Point(0,0);
Point f = new Point(0,0);
Point g = new Point(0,0);
Line aLine = new Line(a,b);
Line bLine = new Line(a,c);
Line cLine = new Line(d,e);
Line dLine = new Line(f,g);
a=null;
b=null;
c=null;
d=null;
e=null;
}
}
如上demo中,引用关系如下图所示,其中a,b,c,d,e对象用完就被赋null
如上图引用dLine对象的两个点f,g,没有被null,引用不被回收所以dline被回收后f,g并不会被回收因此能释放的就是本身的16字节,所以深堆是16
cLine的d和e被赋值null,并且仅仅被Cline引用,所以cline被释放,d,e必然被释放所以深堆16*2+16=48
aLine和bLine两个均持有对方一个点,所以aLine被回收,只有b是只被aline引用所以b被回收,a因为还在bLine中被引用所以不被回收,深堆是16+16=32,bLine同理