Month: March 2013

debug jdk6源码时看不到变量的值怎么办?

从某个时候开始,jdk提供的rt.jar中不再带有符号表,所以debug jdk6源码时一般是看不到变量的值的。 你所能做的就是重新编译一下rt.jar. 我按下面给的步骤试过了,可以用。 http://www.brainbugs.net/post/22537922263/adding-debug-info-to-java-runtime-classes

SecurityManager一般不起作用

在普通webapp、或java application中,如果没有特别指定,System.getSecurityManager()的返回值都是空的,也就是说拿不到SecurityManager,也不会用它去做任何检查。 所以,在这些程序中通过反射直接访问一个对象的私有变量的值,是可以得手的。 有些框架也直接利用这个默认设置来耍流氓,比如Spring的@Resource实现。 但在applet、java web start等环境中SecurityManager默认是有的,这时直接通过反射访问私有变量就会失败。

HashSet和TreeSet如何确定元素的唯一性?

往Set里先后加入两个“有点相像”的对象,最后Set里会有一个对象还是两个? 实验结论如下: HashSet 两个对象是否彼此equals ? 两个对象hashCode是否相等 最终Set大小 备注 true true 1 true false 2 有点违反Set接口契约 false true 2 false false 2 TreeSet TreeSet在判断唯一性时不考虑hash code; 从下面的结果你也可以发现,它连equals()都不理会。 两个对象是否彼此equals ? 两个对象compare后是否相等 最终Set大小 备注 true true 1 true false 2 false true 1 违背了Set接口的契约,令人吃惊? false false 2

HashMap如何应对hash collision ?

HashMap如何应对hash collision?  只通过key的hashCode()来区分key是不够的,因为两个不同key的hash code很容易就重合了。 当hash-code重合时,区分的办法就是 ==和equals()方法了;如果两个key的hashCode()相同而但equals()和==都不同,则将这两个key散列到同一个桶上,但不互相覆盖。 为求明白,可以总结一下equals(), ==, hashCode()呈现不同结果时,HashMap的不同行为: 两个key的hashCode()相等? 两个key是同一个对象? 两个key的equals() == true? 是否导致覆盖 备注 true true true 是 true true false N/A true false true 是 true false false 否 false true true 否 单个key对象存入HashMap后,hashCode发生修改,然后再存一次 false true false N/A false false true 否 false false false 否

并发环境下延迟加载Singleton实例的终极方案:Initialization-on-demand holder idiom

相信你对这个问题已经很熟悉了:并发环境下如何延迟加载Singleton Instance ? public class Expensive { private static Expensive instance; public static Expensive getInstance() { if (instance == null) { instance = new Expensive(); } return instance; } } 如果getInstance()处不使用synchronzied, 可能导致产生两个singleton对象, 或者拿到半残的instance对象。至于臭名昭著的DCL,那就更不必说了。 如果用synchronized, 那可能因为锁的原因在高并发下使性能受损。 最后一招似乎是不使用延迟加载,而是在类初始化时主动生成instance对象; 但是,如果生成这个对象确实很昂贵,而且又很有可能确实用不上它,那主动初始化岂不是很浪费? 《Java并发编程实践》给出了致命一招:Initialization-on-demand holder,即 把instance的初始化投入到一个内部类的初始过程中,就可以兼顾正确性和性能。   1. 内部类的初始化是延迟的,外部类初始化时不会初始化内部类。   2. 内部类的初始化是线程安全的,所以不用担心两个instance或半残instance的问题。   3. 第一次获取instance需要等它初始化,以后再获取就不必了,而且也不需要锁。所以在性能上也是妥妥的。 public class Expensive { private static class LazyHolder …

并发环境下延迟加载Singleton实例的终极方案:Initialization-on-demand holder idiom Read More »

如无必要,尽量不要用ReentrantLock

《JAVA并发编程》这本书说:如无必要,尽量不要用ReentrantLock. 用synchronized关键字就可以了。 因为使用ReentrantLock时必须要记得在finally块里使用unlock(),一旦忘了(发生这种事的概率不低),可能造成很大的悲剧。 ReentrantLock和synchronized的语义是一样的,在JAVA 5里前者性能比后者好很多,但在JAVA 6里两者已经没什么区别了,所以用synchronized不会有性能问题。 ReentrantLock的唯一优势在于它提供了无阻塞加锁、可中断加锁等特性,这对避免死锁有很大帮助。如果你确实需要这些特性,才使用ReentrantLock.

shut down hook示例

package player.kent.chen.learn.sdh; public class HelloShutdownHook { public static void main(String[] args) { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { System.out.println(Thread.currentThread().getName() + "-钩子,再见1"); } }); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { System.out.println(Thread.currentThread().getName() + "-钩子,再见2"); } }); System.out.println(Thread.currentThread().getName() + "-Hello, world!"); } } 输出: 引用 main-Hello, world! Thread-1-钩子,再见2 Thread-0-钩子,再见1 可见:   1. 系统退出时会执行hook里面的操作   2. 这些操作的执行是在独立线程里执行的,而且是异步的 …

shut down hook示例 Read More »

例示CompletionService的使用

它跟普通的Executor + Callable + Future 没什么本质区别。只不过当有多个任务需要提交时,自己手动维护一堆Future、并依次地调用future.get() 会很繁琐。 CompletionService使这个变得简单很多。

活锁(livelock)

活锁(livelock): 没有真正的锁问题,而是进程不停地执行重复的操作,却总是失败。 《JAVA并发编程实践》给出了两个例子: 1. MQ消费者处理消息失败后将消息丢回到队列头部,然后立即马上收到这个消息,然后再处理失败入。。。 2. 两个礼貌的人在路上挡住彼此去路,然后同时往一边让,结果还是互相挡住;然后在同时往另一边让,结果也是互相挡住;然后再往一边让。。。 解决活锁的办法是在操作中引入退出机制,或者引入随机性。