我已经成功地写了一个新的年表,它代表了我的公司的会计日历,基于JodaTime。我参考了大量的JodaTime源代码,以确定我需要做什么。我在BasicChronology类中注意到的一件事是使用内部类YearInfo来缓存'firstDayOfYearMillis‘-自1970-01-01 (国际标准化组织)以来的毫秒数。我认为,如果JodaTime缓存它是一个足够的性能瓶颈,我可能也应该把它添加到我的年表中。
不过,当我这样做的时候,我做了一些修改。具体地说,我将getYearInfo方法移到了YearInfo内部类中,并使其成为静态方法。我还将用于存储缓存值的数组也移到了内部类中。修改后的类的完整定义如下:
/**
* Caching class for first-day-of-year millis.
*
*/
private static final class YearInfo {
/**
* Cache setup for first-day-of-year milliseconds.
*/
private static final int CACHE_SIZE = 1 << 10;
private static final int CACHE_MASK = CACHE_SIZE - 1;
private static transient final YearInfo[] YEAR_INFO_CACHE = new YearInfo[CACHE_SIZE];
/**
* Storage variables for cache.
*/
private final int year;
private final long firstDayMillis;
private final boolean isLeapYear;
/**
* Create the stored year information.
*
* @param inYear The year to store info about.
*/
private YearInfo(final int inYear) {
this.firstDayMillis = calculateFirstDayOfYearMillis(inYear);
this.isLeapYear = calculateLeapYear(inYear);
this.year = inYear;
}
/**
* Get year information.
*
* @param year The given year.
*
* @return Year information.
*/
private static YearInfo getYearInfo(final int year) {
YearInfo info = YEAR_INFO_CACHE[year & CACHE_MASK];
if (info == null || info.year != year) {
info = new YearInfo(year);
YEAR_INFO_CACHE[year & CACHE_MASK] = info;
}
return info;
}
}我的问题是。我的更改对性能或设计有什么影响?我已经决定我的更改应该是线程安全的(给出了关于最终成员变量的答案)。但是为什么最初的实现是这样做的,而不是这样呢?我知道为什么大多数静态使用的方法都不是(给定BasicChronology的子类),但我承认我的一些OO设计材料有点生疏(过去两年一直在使用RPG)。
所以..。有什么想法?
发布于 2011-06-24 07:55:33
关于正确性,通过将YEAR_INFO_CACHE切换为静态,您引入了一个小的内存泄漏。有几种方法可以判断你的静态引用在实践中是否重要,例如,根据你对数据的了解,粗略地估计缓存将增长到多大;在应用程序负载测试期间/之后分析堆;等等。
您正在缓存如此小的对象,以至于您可能会毫不费力地缓存大量对象。尽管如此,如果您发现缓存需要有界,那么您有一些选择,例如LRU缓存,基于软引用而不是直接(强)引用的缓存,等等。但是,我再次强调,对于您的特定情况,实现这些might be a waste of time中的任何一个。
为了解释静态引用的理论问题,我将参考其他帖子,而不是在这里重复它们:
同样在正确性方面,代码是线程安全的,不是因为引用是最终的,而是因为多个线程为某个缓存位置创建的YearInfo值必须相等,所以最终哪个线程在缓存中并不重要。
关于设计,原始Joda代码中所有与YearInfo相关的东西都是私有的,因此YearInfo细节包括缓存都被很好地封装了。这是一件好事。
关于性能,最好的做法是分析代码,并查看哪些代码使用了大量的CPU。对于性能分析,您希望了解花在这段代码上的时间在整个应用程序的上下文中是否重要。在负载下运行你的应用程序,并检查这部分代码是否重要。如果您在没有YearInfo缓存的情况下也看不到这段代码中的性能问题,那么使用/担心该缓存可能不是一个好的时间利用方式。以下是有关如何执行检查的一些信息:
也就是说,相反的是正确的--如果你得到的是有效的,那么就让它保持原样吧!
发布于 2011-08-01 10:01:51
我编写了缓存到YearInfo对象中的原始代码。将更多的逻辑封装到YearInfo类中的解决方案是非常好的,而且应该执行得也很好。我基于意图设计了YearInfo --我只想要一个原始数据对,仅此而已。如果Java支持结构,我会在这里使用一个结构。
至于缓存设计本身,它是基于分析结果来查看它是否有任何影响。在大多数地方,Joda-Time懒惰地计算字段值,缓存它们以供以后使用确实提高了性能。因为这个特定的缓存大小是固定的,所以它不会泄漏内存。它消耗的最大内存量是1024个YearInfo对象,大约是20k字节。
Joda-Time充斥着这样的专用缓存,所有这些缓存都显示出了可测量的性能改进。我不能再说这些技术有多有效了,因为它们是在JDK 1.3上编写和测试的。
https://stackoverflow.com/questions/6458854
复制相似问题