一个简单的Java对象池实现——可用来解决SimpleDateFormat的线程安全问题

来源:互联网 发布:知乎 美国 编辑:程序博客网 时间:2024/06/16 03:35

被SimpleDateFormat的线程安全问题困扰过的人应该不止我一个吧。为了解决这个类的线程安全问题,通常我们会有以下两种做法:

  1. 每次都new 一个SimpleDateFormat对象,但频繁的创建与销毁对象带来的性能问题……哈哈,我就不在这里过多的BB了。
  2. 使用ThreadLocal技术,这恐怕是最常用的一种解决方案,我想几乎每个有经验的Java程序员都使用过它,在此我也不多说啦,如果真有不知到的,且看下面这篇博文:
    SimpleDateFormat的线程安全问题与解决方案

然而,最近在调试过程中意外进入了 XStream这个类库, XStream是一个可以将javaBean与XML双向转换的java类库,本文内容基于xstream-1.4.9版本。所需maven依赖如下:

<dependency>    <groupId>com.thoughtworks.xstream</groupId>    <artifactId>xstream</artifactId>    <version>1.4.9</version></dependency>

不过,本文不是讲解这个类库是如何使用的,而是想说,我在这个类库中发现了一种新颖的可以避免SimpleDateFormat线程安全问题的实现:也即采用对象池,让不同的线程可以使用对象池中不同的SimpleDateFormat对象,并且保证在同一时刻池中的任一对象只能被一条线程使用,从而避免线程安全。

当然XStream中的对象池的实现及其简单,只有简单的借出对象和归还对象,所以完善程度远远无法和apache common pool这种通用且成熟的对象池实现相比(进一个类,数行代码)。不过对于帮助我没理解对象池如何实现到是大有用处。由于实现简单,我就不多解释了,直接贴代码吧。

对象池的简单java实现如下(出自XStream库)

public class Pool {    public interface Factory {        public Object newInstance();    }    private final int initialPoolSize;    private final int maxPoolSize;    private final Factory factory;    private transient Object[] pool;    private transient int nextAvailable;    private transient Object mutex = new Object();    public Pool(int initialPoolSize, int maxPoolSize, Factory factory) {        this.initialPoolSize = initialPoolSize;        this.maxPoolSize = maxPoolSize;        this.factory = factory;    }    public Object fetchFromPool() {        Object result;        synchronized (mutex) {            if (pool == null) {                pool = new Object[maxPoolSize];                for (nextAvailable = initialPoolSize; nextAvailable > 0; ) {                    putInPool(factory.newInstance());                }            }            while (nextAvailable == maxPoolSize) {                try {                    mutex.wait();                } catch (InterruptedException e) {                    throw new RuntimeException("Interrupted whilst waiting " +                            "for a free item in the pool : " + e.getMessage());                }            }            result = pool[nextAvailable++];            if (result == null) {                result = factory.newInstance();                putInPool(result);                ++nextAvailable;            }        }        return result;    }    protected void putInPool(Object object) {        synchronized (mutex) {            pool[--nextAvailable] = object;            mutex.notify();        }    }    private Object readResolve() {        mutex = new Object();        return this;    }}

线程安全的SimpleDateFormat的实现如下(同样出自XStream包):

public class ThreadSafeSimpleDateFormat {    private final String formatString;    private final Pool pool;    public ThreadSafeSimpleDateFormat(String format, int initialPoolSize, int maxPoolSize, final boolean lenient) {        formatString = format;        pool = new Pool(initialPoolSize, maxPoolSize, new Pool.Factory() {            public Object newInstance() {                SimpleDateFormat dateFormat = new SimpleDateFormat(formatString, Locale.ENGLISH);                dateFormat.setLenient(lenient);                return dateFormat;            }        });    }    public String format(Date date) {        DateFormat format = fetchFromPool();        try {            return format.format(date);        } finally {            pool.putInPool(format);        }    }    public Date parse(String date) throws ParseException {        DateFormat format = fetchFromPool();        try {            return format.parse(date);        } finally {            pool.putInPool(format);        }    }    private DateFormat fetchFromPool() {        TimeZone tz = TimeZone.getDefault();        DateFormat format = (DateFormat)pool.fetchFromPool();        if (!tz.equals(format.getTimeZone())) {            format.setTimeZone(tz);        }        return format;    }}
0 0
原创粉丝点击