Java

如无必要,尽量不要用ReentrantLock

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

并发环境下延迟加载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 »

JAVA代码片断:获取当前进程的PID

private static String getPid() throws IOException { Process p = Runtime.getRuntime().exec("/home/kent/opt/jdk1.6.0_41/bin/jps"); InputStream in = p.getInputStream(); List<String> jpsLines = IOUtils.readLines(in); IOUtils.closeQuietly(in); for (String line : jpsLines) { if (line.contains(HelloPoolSize.class.getSimpleName())) { return line.split("\\s")[0]; } } throw new IllegalStateException("拿不到pid"); }

理解ConcurrentModificationException

当一个线程对类集进行迭代时,如果另一个线程修改了类集,迭代线程会发现这个修改,然后就会抛出ConcurrentModificationException . 不过即使出现了上面所说的并发读写,java类集也不能100%保证会抛出ConcurrentModificationException.  因为迭代线程在执行“判断类集是否修改 + 若有则抛出异常”这两步的组合时并没有加锁。 很有可能在 “发现类集没有修改后”, 另一个线程把类集修改了。 另一个要注意的是很多非迭代操作都可能引发ConcurrentModificationException, 因为这些操作隐式地调用了迭代。 比如 类集的hashCode(),equals(), containsAll()等,就连toString()都会,所以,在日志里直接打印类集时,要小心。

ConcurrentHashMap的弱一致性

ConcurrentHashMap提供的迭代器不会抛出ConcurentModificationException,也就是说迭代器如果发现数据被修改了,它会尽量去访问到对Map已做的修改,但这个不能保证。 所以它读到的可能是过期的数据,也就是存在“弱一致性”问题。 对于一个被 并发访问的ConcurrentHashMap来说,size()和isEmpty()往往是不准确的。 但不要误会,以为ConcurrentHashMap的一致性很弱;除了迭代、size()、isEmpty()等操作有这个问题之外,像remove(), put()操作等都比HashMap提供了更高的一致性,因为这些操作都是原子操作。 这些操作中使用了粒度比较细的锁,不会像HashTable一样锁住整个容器,但也不至于像HashMap那样完全不加锁。

例示Executor + Callable + Future的使用

package player.kent.chen.learn.future; import java.io.File; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; public class HelloFuture { public static void main(String[] args) throws Throwable { //一个待完成事项 Callable<String> task = new Callable<String>() { public String call() throws Exception { return FileUtils.readFileToString(new File("/home/kent/temp/1.txt")); } }; //生成executor并异步执行 ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future …

例示Executor + Callable + Future的使用 Read More »

例示FutureTask + Thread

package player.kent.chen.learn.future; import java.io.File; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import org.apache.commons.io.FileUtils; public class HelloFutureTask { public static void main(String[] args) { //一个待完成事项 Callable<String> callable = new Callable<String>() { public String call() throws Exception { return FileUtils.readFileToString(new File("/home/kent/temp/1.txt")); } }; //生成FutureTask对象 FutureTask<String> task = new FutureTask<String>(callable) { @Override //重载这个方法,可以在任务执行完时干点事 protected void done() { super.done(); System.out.println("The task is …

例示FutureTask + Thread Read More »

理解Java Interruption机制

本文内容基本源自 Java theory and practice: Dealing with InterruptedException Interruption机制是干什么用的? Interruption用于一个线程“礼貌地”打断另一个线程,被打断的线程可以理会,也可以不理会。(interruption is a way of politely asking another thread to stop what it is doing if it wants to, at its convenience. ) 不过后面可以看到,不理会者,不是好人(a good citizen) 具体怎么interrupt ? 1. 打断者执行thread.interrupt() 2. 被打断者要么收到InterruptedException, 要么会发现自己的isInterrupted() == true. 注意:    1. 如果被打断者在interruption来临时正在执行sleep(), I/O读写等Blocking Method, 则会收到InterruptedException(所以这些方法一般会throws InterruptedException)    2. 如果被打断者没有执行上述Blocking …

理解Java Interruption机制 Read More »