问题:
Snack类的isExpired方法实现了什么功能?
现有相当大量的snack对象(如一个长度100万的Snack对象数组)需要执行isExpired方法,执行时候发现效率低下, 请分析原因, 并给出优化方案?
为了方便交流学习, 我把完整的题目都贴出来了, 我主要的问题是第二问, 大家有没有好的办法?
代码如下:
public class Snack {
public Snack(String name, Date expirDate){
this.name = name;
this.expireDate = expireDate;
}
private String name;
private Date expireDate;
public boolean isExpired(){
Date now = new Date();
return now.compareTo(this.expireDate) > 0 ;
}
}
Thanks for the invitation.
This can be found on Baidu. Returns true if the current date is greater than the object's expireDate.
My algorithm is not very accurate. Please correct me if I am wrong: first consider whether the expireDate of the objects is in order. Orderly can learn from the idea of binary search. For example, from small to large, if an object can be found, all subsequent objects will return true.
First, you can look at the
Date
对象的compareTo
方法的内部实现,会有clone
operation first, so the overhead increases.1. If
isExpired
方法的作用是判断当前对象是否已过期,如果expireDate
is before the current server time, it is considered not expired, otherwise it is considered expired;2. Since this expression is a bit ambiguous, I will explain it in two situations:
parallel2.1. A Snack array with a length of 100W, traversing and executing the
isExpired
method, the question may be about JVM memory management and garbage collection mechanism, because the program will execute theisExpired
method of these 1 million objects serially (assuming that the cost of creating these objects is ignored), and a newDate object, and
compareTo
will internally perform a clone operation onthis.expireDate
, so the overhead will be relatively large;isExpired
方法,那题目考察的可能是JVM内存管理和垃圾回收机制,因为程序会串行执行这100W个对象的isExpired
方法(假设忽略创建这些对象的开销),而每运行一次就会new一个Date
对象,而compareTo
内部又会对this.expireDate
进行clone操作,所以开销会比较大;2.2、在一定时间段内有大量的Snack对象并行执行
isExpired
2.2. There are a large number of Snacks within a certain period of time If the objectexecutes the
isExpired
method, then the question may focus on high concurrency processing. If you can also relate to the knowledge points of 2.1, you can get extra points;Personally, I think 2.2 is more likely.
expiration time from the business, which is [year | month | day | hour | minutes | seconds | milliseconds]?, the storage and comparison strategies of different precisions can also be different. The higher the precision, the higher the cost.long
或者int
(精度要求不高的情况下)存储expireDate
,如果是2.1,那可以把Date now = new Date()
摞到方法外部(假设对时间的精度要求不是十分高),然后isExperied
方法内部只需要比较now.getTime()
和expireDate
的值即可;如果是2.2且应用部署在集群环境下,那就不能在isExpired
里面生成Date
Talk about my optimization understanding of this code:1. Use the object, because even if there is time synchronization between servers, time inconsistencies may occur. For example, the difference between machine A and machine B is 1 second. This situation is also possible. At this time, you can use a global time generator, and then the application calls this generator to obtain the current server time for comparison; 2. Confirm the accuracy of the
If there is a large amount of data, add an overload to each
isExpired()
中都去取一下时间,会比较耗时。由于是在同一时刻顺序调用数组中每个对象的
isExpired()
,可以假设是在同一时间进行比较,那么给isExpired()
You can do this when calling
Use
System.currentTimeMillis()
to compare timeChange the array into a priority queue, and only need to execute isExpired() on the top element of the heap each time, and the performance is improved from O(n) to O(1)
Now that I see something parallel, I want to use the new API of Java 8, parallel stream, haha, so I simply practiced it, for reference only
Use the traditional compareTo method of Date to compare
Compare using Date’s
System.currentTimeMillis() > expiredDate.getTime()
methodEach comparison method is executed 5 times to facilitate comparison, and each method uses 3 modes to execute
for loop execution mode
Stream loop execution mode
Parallel stream loop execution mode
The code is similar to this:
The final execution result is as follows:
100w level
][2]
1000w level
To sum up: I feel that whether to change the time comparison method or not, judging from the test code, the impact is not big (it may also be related to the specific actual environment), but after adopting the parallel flow method, the execution efficiency has indeed improved, in large quantities When operating arrays or collections, the parallel stream method is better. The JDK will determine the better concurrency mode according to the specific environment
There are two optimization points
1: Creation of Date object
2.compareTo() method
It is said in the question "There are currently a large number of snack objects (such as a Snack object array with a length of 1 million) that need to execute the isExpired method, and the efficiency is found to be low during execution"
There are two core problems here, and I don’t know which one to solve.
Having a large number of objects to solve?
2. To solve the inefficiency of execution.
Question 1,
Clear the array of 10,000 objects. There just isn’t that much to do.
Question 2,
Delete the code executed in the isExpire() method. This method does nothing and the execution efficiency is high.