日志标签:java

[读书笔记]《Java Performance》GC(1)

分类:java评论:2条作者:ticmy日期:2013-05-17

Throughput GC指定方式: -XX:+UseParallelOldGC 或 -XX:+UseParallelGC,两者的区别是,-XX:+UseParallelOldGC同时激活新生代并行垃圾回收和老年代的并行垃圾回收,亦即,Minor GC和Full GC都是多线程的;-XX:+UseParallelGC只会激活新生代的并行垃圾回收。也就是使用了-XX:+UseParallelOldGC会自动激活-XX:+UseParallelGC。 在生产系统中,推荐打印出垃圾收集日志,开销很小,但能提供很多信息。推荐的命令行选项的最小集:-XX:+PrintGCTimestamps -XX:+PrintGCDetails -Xloggc:<fileName> -XX:+PrintGCDateStamps打印出的是日期,要求Java 6 Update 4及以上版本;-XX:+PrintGCTimeStamps打印出的是相对于JVM启动的时间偏移量。 老年代使用CMS(-XX:+UseConcMarkSweepGC),配合其使用的新生代垃圾收集器为多线程的ParNew;老年代使用Serial GC,配合其使用的新生代为单线程的DefNew。 为低等待时间(STW停顿)调优时,可以使用这两个选项: -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime 重视吞吐…
Tags: ,

ScheduledThreadPoolExecutor实现原理

分类:java, 并发评论:7条作者:ticmy日期:2013-01-09

自jdk1.5开始,Java开始提供ScheduledThreadPoolExecutor类来支持周期性任务的调度,在这之前,这些工作需要依靠Timer/TimerTask或者其它第三方工具来完成。但Timer有着不少缺陷,如Timer是单线程模式,调度多个周期性任务时,如果某个任务耗时较久就会影响其它任务的调度;如果某个任务出现异常而没有被catch则可能导致唯一的线程死掉而所有任务都不会再被调度。ScheduledThreadPoolExecutor解决了很多Timer存在的缺陷。 先来看看ScheduledThreadPoolExecutor的实现模型,它通过继承ThreadPoolExecutor来重用线程池的功能,里面做了几件事情: 为线程池设置了一个DelayedWorkQueue,该queue同时具有PriorityQueue(优先级大的元素会放到队首)和DelayQueue(如果队列里第一个元素的getDelay返回值大于0,则take调用会阻塞)的功能 将传入的任务封装成ScheduledFutureTask,这个类有两个特点,实现了java.lang.Comparable和java.util.concurrent.Delayed接口,也就是说里面有两个重要的方法:compareTo和getDelay。ScheduledFutureTask里面存储了该任务距离下次调度还需要的时间(使用的是基于System#nanoTime实现的相对时间,不…

[翻译]JSR 133 (Java Memory Model) FAQ

分类:java, 并发, 翻译评论:9条作者:ticmy日期:2012-12-11

JSR 133 (Java Memory Model) FAQ Jeremy Manson and Brian Goetz, February 2004 内容列表 究竟什么是内存模型? 其它语言,像C++,有内存模型吗? JSR133是什么? 重排序意味着什么? 老的内存模型有什么问题? 未正确同步是什么意思? 同步做了什么? final字段的值是如何看起来会变的? 在新的JMM下final字段是怎么工作的? volatile做了什么? 新的内存模型修复了“双重锁定检查”问题吗? 如果我要写一个VM呢? 为什么我要关心Java内存模型? 究竟什么是内存模型? 在多处理器系统中,处理器通常都有一到多级存储缓存,通过加速数据访问(因为数据距处理器更近)以及减少存储总线的流量(因为本地缓存可以满足某些存储操作)以提升性能。存储缓存能极大地提升性能,但也面临着大量新的难题。例如,当两个处理器同时检查相同的内存地址时会怎么样?在什么条件下它们将看到相同的值? 在处理器层面,针对其它处理器写入内存的值何时对当前处理器可见,以及当前处理器写入的值何时对其它处理器可见,内存模型为它们定义了充要条件。有些处理器表现出了强内存模型,对于任一给定的内存地址所有处理器看到的总是相同的值。另一些处理器则表现出…

hotspot中Thread#isInterrupted的并发可见性bug

分类:java, 并发评论:2条作者:ticmy日期:2012-11-14

这是在concurrency-interest邮件列表看到的一个hotspot bug。 在《The Java Language Specification Java SE 7 Edition》中17.4.4Synchronization Order小节中有这么一句描述: If thread T1 interrupts thread T2, the interrupt by T1 synchronizes-with any point where any other thread (including T2) determines that T2 has been interrupted(by having an InterruptedException thrown or by invoking Thread.interrupted or Thread.isInterrupted). 线程t1 interrupt了线程t2,那么线程t2调用Thread.isInterrupted就会返回true,然而在hotspot几个版本中却没有体现出来,测试代码如下: public class InterruptedVisibilityTest { public void think() { System.out.println("新线程正在执行"); while (true) { if (checkInterruptedStatus()) break; } System.out.println("新线程退出循环"); } private boolean checkInterruptedStatus() { return Thread.currentThread().isInterrupted(); } public stati…

ScheduledThreadPoolExecutor与System#nanoTime

分类:java, 并发评论:1条作者:ticmy日期:2012-11-13

一直流传着Timer使用的是绝对时间,ScheduledThreadPoolExecutor使用的是相对时间,那么ScheduledThreadPoolExecutor是如何实现相对时间的? 先看看ScheduledThreadPoolExecutor中实现定时调度的模型,很简单,内部用了无界的DelayQueue作为线程池的队列,而DelayQueue的内部又使用的是一个PriorityQueue,那么,最先需要定时调度的任务位于队首。定时任务实现逻辑大概如此:创建ScheduledThreadPoolExecutor对象的时候会记录一个常量值t,定时任务中有一个以t为基础的多久以后会被执行的属性,在线程拿到队首任务(可能等待了一段时间)执行后,会修改这个属性为下一次要执行的基于t的时间量,然后将其再放入队列中。整个逻辑都在任务的run方法中: public void run() { if (isPeriodic()) runPeriodic(); else ScheduledFutureTask.super.run(); } 如果是周期性任务,会执行runPeriodic: private void runPeriodic() { boolean ok = ScheduledFutureTask.super.runAndReset(); boolean down = isShutdown(); // Reschedule if not cancelled and not shutdown or policy allows if (ok && (!down…

对象实例化的顺序

分类:java, 基础评论:6条作者:ticmy日期:2012-11-08

创建一个对象大概有以下几种方式: 1、通过new关键字,如new Object(); 2、通过某些反射类的newInstance方法,如Class#newInstance、Constructor#newInstance; 3、如果对象是Cloneable的,通过clone方法; 4、通过ObjectInputStream#readObject反序列化; 以上是通过java程序可以创建出对象的方式,jvm中还有一些隐式创建对象的地方,譬如: 1、启动一个类,main方法的参数String数组是隐式创建的,如果指定了一个或多个String对象,还要创建这些String对象; 2、读入一个class二进制数据的时候,创建一个与之对应的java.lang.Class类的对象; 3、在使用“+”进行字符串变量连接时,可能会创建StringBuffer/StringBuilder对象; 如此等等。 那么,在程序中通过new或newInstance创建对象(后面说创建对象均指这两种方式)的时候,构造方法、实例变量、父类构造方法、父类实例变量等的执行顺序是怎样的? 在创建对象的时候,首先会分配内存,此时所有实例变量均为默认值,然后做初始化实例变量、构造方法调用等操作。对于类变量,在创建对象之前,加载类的时候已经做掉了,这里为避免干扰,忽略掉。 先来一个例子: public class Init { public static v…