记一次代码优化
最近接到了一个任务
背景:
由于客户的数据量突然增长很多(3~5倍),原先的程序运行耗时非常多,之前由于数据量小没有暴露出来
任务:
优化代码,使耗时减少
一、带返回值的线程池
组长建议将线性运行改为并发,使用带返回值的线程池,并给了以下示例代码:
import java.util.ArrayList; 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; class TaskCallable implements Callable<String>{ private int id; private ExecutorService exe; TaskCallable(int id,ExecutorService exe){ this.id = id; this.exe = exe; } @Override public String call() throws Exception { Thread.sleep(5000); return "result of taskWithResult "+id+";"+exe.toString(); } } public class Test { public static void main(String[] args) { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2); ArrayList<Future<String>> results = new ArrayList<Future<String>>(); for (int i = 0; i < 20; i++) { // 调用submit方法来执行TaskCallable中的call方法,并将该方法返回值添加到results列表中 results.add(fixedThreadPool.submit(new TaskCallable(i,fixedThreadPool))); System.out.println("add:"+i); } for(int j = 0;j < 20; j++) { try { System.out.println(results.get(j).get()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } fixedThreadPool.shutdown(); System.out.println("finsh"); } }
由于之前没有接触过这种线程池,于是先对其了解了一番,大概知道了以下几点:
1、ExecutorService 的 submit 方法会立刻返回一个 Future 对象
回到上面的代码,虽然被 submit 的那些任务的执行顺序不确定,但是由于 Future 对象是立即被返回的,所以后面取线程运行结果的时候,可以保证两个集合之间的对应关系不会错乱
2、Future 的 get 方法会引起阻塞
即,当我们使用 Future 的 get 方法获取线程运行结果时,当前线程会阻塞,直到执行该任务的线程执行完毕,返回结果为止
3、当 ExecutorService 的 submit 方法被调用时,真正工作的方法是在任务类里面定义的 call 方法
二、维护别人的代码
由于这个项目之前不是由我开发的,所以对代码其实很陌生
在问清楚了这次任务主要改动的类之后,我做了一下两件事情,感觉对理清逻辑还是很有帮助的:
1、弄清楚该类中,各方法间的调用关系,并以如下的方式写下来(尽量按照调用顺序从上往下写)
2、弄清楚涉及到几个数据源,分别涉及到哪些表,以及数据的流转是怎样的,即从哪个数据库的哪些表里取数据,要往哪个数据库的哪张表里写数据,并写下来
注:在以上两点中,我都提到了要把成果写下来,这是因为写下来就相当于为以后奠基,每次看的时候,都可以站在以前的经验之上去看,这样会省事很多
三、进一步优化
在线性改并行完成之后,在与实施同事联调的时候,他又反馈了一个效率方面的问题,即代码的某一块从数据库查询数据和插入数据到数据库,非常耗时
由于没有注释,而且业务逻辑有些复杂,我在相关代码那里研究了两天的时间,都没有想到一个好的解决办法
跟组长讨教,组长先问了一句,数据库加索引没有。。。
竟然忘了这一茬,之前只是了解过索引的作用,然后自己做了一个小测试,没有在实战中使用过,所以关键时候根本想不起来
一看,果然没加,加了索引之后,效率提高了 24 倍,真是惊呆了我和实施同事
这里想说,实战很重要,抬起头来看路也很重要,不能只把眼光局限于自己的一亩三分地