jvm 手动触发gc
很多时候我们在学习JVM时,往往需要查看JVM的回收日志,查看JVM的相关运行参数,这时候我们可以通过手动触发的形式获取JVM的运行回收情况。
加上参数
-Xms1024m -Xmx1024m -Xmn512m -XX:+PrintGCDetails。
代码1234567891011121314151617public class TestGCRoots01 { private int _10MB = 10 * 1024 * 1024; private byte[] memory = new byte[8 * _10MB]; public static void main(String[] args) { method01(); System.out.println("返回main方法"); System.gc(); System.out.println("第二次GC完成"); } public static void method01() { ...
java反射05-Constructor对象
前言Constructor 对象,就是字面意思,就是一个构造器对象。可以通过它构建对象。
有构造器就能创建对象。构造器对象,用来获取当前反射类的构造器。
主要方法:
getDeclaredConstructor:根据方法签名,获取构造器,可返回 private public 等。
getConstructor: 只能返回 public 的构造器
反射获得 Constractor这里是创建一个对象,不包括调用。
1234567public void test() { Class cls = Class.forName("com.liukai.Person"); //获取指定的对象(公共的) Constructor constructor = cls.getConstructor(); // 创建一个对象 Object p = constructor.newInstance();}
再举个例子,通过getDeclaredConstructor获取指定方法签名的构造器。方法:Constructor.getDeclaredConstruc ...
java反射04-获取方法调用栈
前言实际开发中,有多个接个有多个实现类时,搞不清调用栈,可以用这个方法来查看。
实现实现方式,通过拿到当前线程的所有调用栈信息,再遍历输出即可,虽然简单吧,但是实用呀,有时候一个方法报错了,没有异常调用栈,就比较难受了,加上这个方法,自己打调用栈。
获取方法调用栈方式:
1Thread.currentThread().getStackTrace();
代码比较简单,如下:
12345678910111213141516171819202122232425262728293031323334public class Test { public static void main(String[] args) { //打印所有调用栈 testInvoke(); } public static void testInvoke() { defaultTag(); } private static String defaultTag() { StackTraceElement[] stackTrace ...
竟态条件 racing condition
竟态条件 racing condition多个线程读时,线程是安全的。当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件。我的理解,竞态条件就是一种情况。
代码示例假设有 A、B 两个线程,调用 add 方法分别传入 1 和 2,理想条件下结果应该是 3。现在出现了不安全的情况,有可能结果不对。add 方法就是临界区,count 就是同一资源。
123456class Counter { protected long count = 0; public void add(long value) { this.count = this.count + value; } }
其实这样一看,说白了,就是要严格控制线程的执行顺序,假设是按A、B的顺序执行来讲,B依赖于A先执行完成,B再执行结果才是正确的,中间不能出现问题,否则如果,中间交叉执行,就有可能发生了竞态条件。
java 注解简述
前言注解(annotation)相当于一个运行于内存当中的自定义类型的数据存储区域,理解以后才发现它的好用,就是数据存储区,相当于一个运行在内存当中的XML,所有的注解数据在JDK加载完类以后,就可以被使用。
JDK内置注解三个基本内置注解:1.@override2.@Deprecated //加在类或方法上,标注为过时3.@SuppressWarnings //制编译器
元注解 MetaData元注解使用和创建注解的方式,让自己可以创建自己的注解。元数据/元注解作用:就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation 类型作说明。
Java5.0定义的元注解:@Documented 标记生成javadoc@Inherited 标记继承关系@Retention 注解的生存期@Target 标注的目标
@Target 注解说明了Annotation所修饰的对象范围:
Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)
类型成员(方法、构造方法、 ...
简单说明 lock 锁和 Condition 的操作
作用:使当前线程进入等待状,并交换执行执,等待被交换的当前执行线程唤醒,才可以继续执行,如果不被唤醒?场景:多个线程操作同一个共享资源时使用。
Condition 是执行条件。类似传统技术中的 wait 的 notify 功能。Condition 是基于一个 lock 而存在。注意的是,Condition 的创建来自同一个 lock 对象,
Condition 也行 wait 也好,套路就是使用三个工具来完成三步套路。即,用两个线程,同时跑两个代码,并且用 while 不段的去读取一个条件,来判断自己是否应该唤醒对方。
步骤:
先lock住
通过 lock 拿到 condition。再进行操作如 await
然后多个线程开始 await、single注意 await 会释放锁。
1await()的作用是能够让其他线程访问竞争资源,所以挂起状态就是要释放竞争资源的锁。
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585 ...
java 程序驻留不退出保持运行
前言不管是C、java、go 程序,要让程序一直不间断动行,就肯定需要保持线程不退出,才能可能持续运行。
今天说的是java,一般来说从main方法开始运行结束之后,线程也就退出,如何保证线程不退出?实际上只要证保有一个线程在持续运行,程序就不算退出。一般来说只需要保持main线程不退出,然后其他线程不间断的工作就OK。实际上在如果开启多个线程,就算主线程执行结束了,子线程没有结整,JVM一样不会退出。
保持运行上面说了,思路都量样的,就是阻塞一条线程,让JVM不要退出,一般是阻塞主线程main,让他阻塞不退出,直到需要退出的时候再限出。演示几种不退出的方式:
读取流: System.in.read();
等待锁:
wait()
CountDownLatch(1).await();
死循环: while(true)
睡眠: sleep()
这几种方式,不是阻塞,就是睡眠,大概思路都差不多,就是
读取流通过阻塞主线程,来验证一下,运行后就可以看到service的run方法执行完后,程序也不会退的。代码可以自行复制验证。这种方式可以用,一般线上服务都是通过kill -15来退出应用 ...
JVM 分代的概念
堆,才有分代的概念。堆,才有分代的概念。堆,才有分代的概念。
分代JVM 将内存分为大致分为三个区域,1.8 前后有区别
为什么要分代
不分代行不行
不分代完全可以,但是分代的唯一理由是为了优化GC性能。怎么优化?如果不进行分代,每次GC都要把整片堆扫一遍来寻找垃圾对象,太慢。分代直接把对象创建到某一个分代区,这样GC就可以针对这一分代区域就行优化,就不费劲了。
年轻代
eden、survivor、from、to
年轻代分三个部分:
Eden 区,即新生对象区,除大对象以外,新生对象都创建在这里。
Survivor 区,即幸存区,该区域又分两个空间s0 和 s1 分别也叫 from 和 to,默认比例8:1。
对象经历的过程
新创建对象,分配到Eden区,除大对象特殊处理。
在 Eden 区经过一次GC后,如果仍存活,移到 Survivor。
在 Survivor 中又经历一次 GC,年龄会增加一岁。
年龄到一定程度,移到老年代。
年轻代使用什么GC算法
是复制算法。
为什么选复制算法?因为:年轻代中的80%以上的对象很快就死亡。所以,在年轻代的垃圾回收算法使用 ...
wait-notify 实现生产者消费者模式
wait 和 nofity 在线程中的搭配使用,其实就是生产者消费者的一种应用。
一、为什么要有生产者消费者模式在实际应使用多线程时,线程间的角色并不一完全一样的,有的线程负责生产数据,有的线程负责消费数据。所在就会有一种情况,就是: 生产者生产数据太快,消费者消费能力跟不上。
比较线程A 不断的new 对象,并将对象放到一个队列里,而线程B,不断的从队列里拿出数据进行逻辑操作。显然线程A new 对象这一操作会更快,如果一直持续下去内存有可能会被撑暴。
解决这个问题的思路之一就是:生产者-消费者模式
二、wait、notify 简单应用示例Wait 类12345678910111213141516171819202122232425262728293031323334public class SimpleWaitTest implements Runnable { private Object object; public SimpleWaitTest(Object object) { this.object = object; ...
java 序列化使用
简述开始前先搞清楚一个问题什么是序列化?就是一个目的:将 JAVA 对象转换成二进制的数据进行各种操作,如传输、保存、增删等。是的,你没看错,就是要转成二进制的数据。
主要聊三个问题:Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?
还是一样,先说怎么用,再说为什么。
使用这次的示例是准备了几种场景:
序列化后文件存储
序列化后内存中使用
java当中提供了原生序列化方式,也就是把内存中的数据,转换成二进制,或者把二进制数据,转换成内存数据的API。在java的世界中,二进制数据称为流,通过流,也就是抽象成一个个流对象进行处理。
序列化并持久化首先第一步,需要实现序列化接口,才能被序列化。
123456789101112public class TestObj2 implements Serializable { private String name; public String getName() { return name; } public void setName(String na ...