做为一个Java后端开发,咱们写出的大部分代码都决定着用户的使用体验。若是咱们的后端代码性能很差,那么用户在访问咱们的网站时就要浪费一些时间等待服务器的响应。这就可能致使用户投诉甚至用户的流失。java
关于性能优化是一个很大的话题。《Java程序性能优化》说性能优化包含五个层次:设计调优、代码调优、JVM调优、数据库调优、操做系统调优等。而每个层次又包含不少方法论和最佳实践。本文不想大而广的概述这些内容。只是举几个经常使用的Java代码优化方案,读者看完以后能够真正的实践到本身代码中的方案。算法
对于IO处理、数据库链接、配置文件解析加载等一些很是耗费系统资源的操做,咱们必须对这些实例的建立进行限制,或者是始终使用一个公用的实例,以节约系统开销,这种状况下就须要用到单例模式。数据库
单例模式有不少种语法,个人公众号也推送过多篇和单例相关的文章编程
假设一个任务执行起来须要花费一些时间,为了省去没必要要的等待时间,能够先获取一个“提货单”,即Future,而后继续处理别的任务,直到“货物”到达,即任务执行完获得结果,此时即可以用“提货单”进行提货,即经过Future对象获得返回值。后端
public class RealData implements Callable<String> {
protected String data;
public RealData(String data) {
this.data = data;
}
@Override
public String call() throws Exception {
//利用sleep方法来表示真是业务是很是缓慢的
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return data;
}
}
public class Application {
public static void main(String[] args) throws Exception {
FutureTask<String> futureTask =
new FutureTask<String>(new RealData("name"));
ExecutorService executor =
Executors.newFixedThreadPool(1); //使用线程池
//执行FutureTask,至关于上例中的client.request("name")发送请求
executor.submit(futureTask);
//这里能够用一个sleep代替对其余业务逻辑的处理
//在处理这些业务逻辑过程当中,RealData也正在建立,从而充分了利用等待时间
Thread.sleep(2000);
//使用真实数据
//若是call()没有执行完成依然会等待
System.out.println("数据=" + futureTask.get());
}
}
复制代码
合理利用线程池可以带来三个好处。第一:下降资源消耗。经过重复利用已建立的线程下降线程建立和销毁形成的消耗。第二:提升响应速度。当任务到达时,任务能够不须要等到线程建立就能当即执行。第三:提升线程的可管理性。线程是稀缺资源,若是无限制的建立,不只会消耗系统资源,还会下降系统的稳定性,使用线程池能够进行统一的分配,调优和监控。缓存
在 Java 5 以后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor 框架即是 Java 5 中引入的,其内部使用了线程池机制,它在 java.util.cocurrent 包下,经过该框架来控制线程的启动、执行和关闭,能够简化并发编程的操做。性能优化
public class MultiThreadTest {
public static void main(String[] args) {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-%d").build();
ExecutorService executor = new ThreadPoolExecutor(2, 5, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("hello world !");
}
});
System.out.println(" ===> main Thread! " );
}
}
复制代码
JDK自1.4起开始提供全新的I/O编程类库,简称NIO,其不但引入了全新高效的Buffer和Channel,同时,还引入了基于Selector的非阻塞 I/O机制,将多个异步的I/O操做集中到一个或几个线程当中进行处理,使用NIO代替阻塞I/O能提升程序的并发吞吐能力,下降系统的开销。服务器
对于每个请求,若是单独开一个线程进行相应的逻辑处理,当客户端的数据传递并非一直进行,而是断断续续的,则相应的线程须要 I/O等待,并进行上下文切换。而使用NIO引入的Selector机制后,能够提高程序的并发效率,改善这一情况。网络
public class NioTest {
static public void main( String args[] ) throws Exception {
FileInputStream fin = new FileInputStream("c:\\test.txt");
// 获取通道
FileChannel fc = fin.getChannel();
// 建立缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 读取数据到缓冲区
fc.read(buffer);
buffer.flip();
while (buffer.remaining()>0) {
byte b = buffer.get();
System.out.print(((char)b));
}
fin.close();
}
}
复制代码
在并发场景中,咱们的代码中常常会用到锁。存在锁,就必然存在锁的竞争,存在锁的竞争,就会消耗不少资源。那么,如何优化咱们Java代码中的锁呢?主要能够从如下几个方面考虑:多线程
关于锁优化的内容,后面会出一篇文章详细介绍。
在进行数据传输以前,能够先将数据进行压缩,以减小网络传输的字节数,提高数据传输的速度,接收端能够将数据进行解压,以还原出传递的数据,而且,通过压缩的数据还能够节约所耗费的存储介质(磁盘或内存)的空间以及网络带宽,下降成本。固然,压缩也并非没有开销的,数据压缩须要大量的CPU计算,而且,根据压缩算法的不一样,计算的复杂度以及数据的压缩比也存在较大差别。通常状况下,须要根据不一样的业务场景,选择不一样的压缩算法。
对于相同的用户请求,若是每次都重复的查询数据库,重复的进行计算,将浪费不少的时间和资源。将计算后的结果缓存到本地内存,或者是经过分布式缓存来进行结果的缓存,能够节约宝贵的CPU计算资源,减小重复的数据库查询或者是磁盘I/O,将本来磁头的物理转动变成内存的电子运动,提升响应速度,而且线程的迅速释放也使得应用的吞吐能力获得提高。
Java多线程编程中Future模式的详解 java锁优化的方法与思路