happens-before俗解

分类:java, 并发评论:11条作者:ticmy日期:2013-11-17

学习Java并发,到后面总会接触到happens-before偏序关系。初接触玩意儿简直就是不知所云,下面是经过一段时间折腾后个人对此的一点浅薄理解,希望对初接触的人有帮助。如有不正确之处,欢迎指正。 synchronized、大部分锁,众所周知的一个功能就是使多个线程互斥/串行的(共享锁允许多个线程同时访问,如读锁)访问临界区,但他们的第二个功能 —— 保证变量的可见性 —— 常被遗忘。 为什么存在可见性问题?简单介绍下。相对于内存,CPU的速度是极高的,如果CPU需要存取数据时都直接与内存打交道,在存取过程中,CPU将一直空闲,这是一种极大的浪费,妈妈说,浪费是不好的,所以,现代的CPU里都有很多寄存器,多级cache,他们比内存的存取速度高多了。某个线程执行时,内存中的一份数据,会存在于该线程的工作存储中(working memory,是cache和寄存器的一个抽象,这个解释源于《Concurrent Programming in Java: Design Principles and Patterns, Second Edition》§2.2.7,原文:Every thread is defined to have a working memory (an abstraction of caches and registers) in which to store values. 有不少人觉得working memory是内存的某个…

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

分类:java评论:5条作者:ticmy日期:2013-06-22

计算LiveData Size Live Data Size是应用运行稳定,经历过Full GC之后老年代和永久代的堆内存占用。最好是观察多次取均值。 强制Full GC:jmap –histo:live <pid> <pid>可以通过jps命令获得。 初始堆大小 一般,-Xms和-Xmx的初始值应当设为老年代Live Data Size的3到4倍;-XX:PermSize和-XX:MaxPermSize的初始值应当设为永久代Live Data Size的1.2到1.5倍;新生代的初始大小应当设为老年代Live Data Size的1到1.5倍。 为低延迟/响应性调优 如果吞吐量GC的持续时间或频度比应用要求高很多的话,考虑换CMS。 细化新生代大小 尽管Minor GC的时间与新生代中可触及的对象数有关,但一般来说,新生代越小,Minor GC耗时越短,但,减少新生代的大小,会增加Minor GC的频度。因为在相同的对象分配速率下,新生代越小,满的越快;相反,增加新生代的大小会降低Minor GC的频度。 若发现Minor GC耗时太长,正确的做法是减小新生代的大小;若Minor GC太频繁,正确的做法是加大新生代的大小。 在改变新生代大小时,注意保持老年代不变。 根据计算,得到大概的对象分配速率。在增大新生代以减低频度的时候,计算出大概…

[读书笔记]《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: ,

wait操作无故退出?

分类:java, 并发评论:5条作者:ticmy日期:2013-04-05

前不久在网上看到这样一个例子: class MyThread extends Thread { public void run() { System.out.println(getName() + "开始sleep"); try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } System.out.println(getName() + "结束sleep"); } } public class TestWaitNotify { public static void main(String[] args) throws Exception { Thread myThread = new MyThread(); myThread.start(); synchronized (myThread) { myThread.wait(); } System.out.println("wait结束."); } } myThread执行结束后,main线程中的wait操作就自动退出了。程序里也并没有看到有notify/notifyAll调用。 如果将程序改成下面这样: class MyThread extends Thread { public void run() { System.out.println(getName() + "开始sleep"); try { Thread.sleep(2000); } catch (Exception e) { e.print…

ScheduledThreadPoolExecutor实现原理

分类:java, 并发评论:6条作者: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, 并发, 翻译评论:7条作者: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内存模型? 究竟什么是内存模型? 在多处理器系统中,处理器通常都有一到多级存储缓存,通过加速数据访问(因为数据距处理器更近)以及减少存储总线的流量(因为本地缓存可以满足某些存储操作)以提升性能。存储缓存能极大地提升性能,但也面临着大量新的难题。例如,当两个处理器同时检查相同的内存地址时会怎么样?在什么条件下它们将看到相同的值? 在处理器层面,针对其它处理器写入内存的值何时对当前处理器可见,以及当前处理器写入的值何时对其它处理器可见,内存模型为它们定义了充要条件。有些处理器表现出了强内存模型,对于任一给定的内存地址所有处理器看到的总是相同的值。另一些处理器则表现出…