记一次代码优化

 

最近接到了一个任务

背景:

由于客户的数据量突然增长很多(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、弄清楚该类中,各方法间的调用关系,并以如下的方式写下来(尽量按照调用顺序从上往下写)

execute → getConnection
execute → saveFile → createDirectory
execute → saveFile → downFile → doSomething
execute → saveFile → writeNewFile → do1
execute → saveFile → writeNewFile → do2
execute → saveFile → writeNewFile → do3

2、弄清楚涉及到几个数据源,分别涉及到哪些表,以及数据的流转是怎样的,即从哪个数据库的哪些表里取数据,要往哪个数据库的哪张表里写数据,并写下来

 

注:在以上两点中,我都提到了要把成果写下来,这是因为写下来就相当于为以后奠基,每次看的时候,都可以站在以前的经验之上去看,这样会省事很多

 

 

三、进一步优化

 

在线性改并行完成之后,在与实施同事联调的时候,他又反馈了一个效率方面的问题,即代码的某一块从数据库查询数据和插入数据到数据库,非常耗时

 

由于没有注释,而且业务逻辑有些复杂,我在相关代码那里研究了两天的时间,都没有想到一个好的解决办法

 

跟组长讨教,组长先问了一句,数据库加索引没有。。。

 

竟然忘了这一茬,之前只是了解过索引的作用,然后自己做了一个小测试,没有在实战中使用过,所以关键时候根本想不起来

 

一看,果然没加,加了索引之后,效率提高了 24 倍,真是惊呆了我和实施同事

 

这里想说,实战很重要,抬起头来看路也很重要,不能只把眼光局限于自己的一亩三分地

 

posted @ 2019-05-12 17:06  stoneBlog  阅读(105)  评论(0编辑  收藏  举报