作为一个Java后端开发,我们写出的大部分代码都决定着用户的使用体验。如果我们的后端代码性能不好,那么用户在访问我们的网站时就要浪费一些时间等待服务器的响应。这就可能导致用户投诉甚至用户的流失。

关于性能优化是一个很大的话题。《Java程序性能优化》说性能优化包含五个层次:设计调优、代码调优、JVM调优、数据库调优、操作系统调优等。而每一个层次又包含很多方法论和最佳实践。本文不想大而广的概述这些内容。只是举几个常用的Java代码优化方案,读者看完之后可以真正的实践到自己代码中的方案。

使用单例

对于IO处理、数据库连接、配置文件解析加载等一些非常耗费系统资源的操作,我们必须对这些实例的创建进行限制,或者是始终使用一个公用的实例,以节约系统开销,这种情况下就需要用到单例模式。

单例模式有很多种语法,我的公众号也推送过多篇和单例相关的文章

使用Future模式

假设一个任务执行起来需要花费一些时间,为了省去不必要的等待时间,可以先获取一个“提货单”,即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! " );
}
}

使用NIO

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代码中的锁呢?主要可以从以下几个方面考虑:

  • 减少锁持有时间

    • 可以使用同步代码块来代替同步方法。这样既可以减少锁持有的时间。
  • 减少锁粒度
    • 要在并发场景中使用Map的时候,记得使用ConcurrentHashMap来代替HashTable和HashMap。
  • 锁分离
    • 普通锁(如syncronized)会导致读阻塞写、写也会阻塞读,同时读读与写写之间也会进行阻塞,可以想办法将读操作和写操作分离开。
  • 锁粗化
    • 有些情况下我们希望把很多次锁的请求合并成一个请求,以降低短时间内大量锁请求、同步、释放带来的性能损耗。
  • 锁消除
    • 锁消除是Java虚拟机在JIT编译是,通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过锁消除,可以节省毫无意义的请求锁时间。

关于锁优化的内容,后面会出一篇文章详细介绍。

压缩传输

在进行数据传输之前,可以先将数据进行压缩,以减少网络传输的字节数,提升数据传输的速度,接收端可以将数据进行解压,以还原出传递的数据,并且,经过压缩的数据还可以节约所耗费的存储介质(磁盘或内存)的空间以及网络带宽,降低成本。当然,压缩也并不是没有开销的,数据压缩需要大量的CPU计算,并且,根据压缩算法的不同,计算的复杂度以及数据的压缩比也存在较大差异。一般情况下,需要根据不同的业务场景,选择不同的压缩算法。

缓存结果

对于相同的用户请求,如果每次都重复的查询数据库,重复的进行计算,将浪费很多的时间和资源。将计算后的结果缓存到本地内存,或者是通过分布式缓存来进行结果的缓存,可以节约宝贵的CPU计算资源,减少重复的数据库查询或者是磁盘I/O,将原本磁头的物理转动变成内存的电子运动,提高响应速度,并且线程的迅速释放也使得应用的吞吐能力得到提升。

人人都能掌握的Java服务端性能优化方案的更多相关文章

  1. Java服务端性能优化

    <Java程序性能优化>说性能优化包含五个层次:设计调优.代码调优.JVM调优.数据库调优.操作系统调优. 常用的几个代码优化方案: 使用单例 对于IO处理.数据库连接.配置文件解析加载等 ...

  2. 俯瞰 Java 服务端开发

    原文首发于 github ,欢迎 star . Java 服务端开发是一个非常宽广的领域,要概括其全貌,即使是几本书也讲不完,该文将会提到许多的技术及工具,但不会深入去讲解,旨在以一个俯瞰的视角去探寻 ...

  3. RPC学习--C#使用Thrift简介,C#客户端和Java服务端相互交互

    本文主要介绍两部分内容: C#中使用Thrift简介 用Java创建一个服务端,用C#创建一个客户端通过thrift与其交互. 用纯C#实现Client和Server C#服务端,Java客户端 其中 ...

  4. ajax跨域请求,页面和java服务端的写法

    方法一(jsonp): 页面ajax请求的写法: $.ajax({ type : "get", async : false, cache : false, url : " ...

  5. Flex通信-Java服务端通信实例

    转自:http://blessht.iteye.com/blog/1132934Flex与Java通信的方式有很多种,比较常用的有以下方式: WebService:一种跨语言的在线服务,只要用特定语言 ...

  6. “快的打车”创始人陈伟星的新项目招人啦,高薪急招Java服务端/Android/Ios 客户端研发工程师/ mysql DBA/ app市场推广专家,欢迎大家加入我们的团队! - V2EX

    "快的打车"创始人陈伟星的新项目招人啦,高薪急招Java服务端/Android/Ios 客户端研发工程师/ mysql DBA/ app市场推广专家,欢迎大家加入我们的团队! - ...

  7. C#使用Thrift简介,C#客户端和Java服务端相互交互

    C#使用Thrift简介,C#客户端和Java服务端相互交互 本文主要介绍两部分内容: C#中使用Thrift简介 用Java创建一个服务端,用C#创建一个客户端通过thrift与其交互. 用纯C#实 ...

  8. 支付宝ios支付请求Java服务端签名报的一个错(ALI40247) 原创

    今天做app的支付宝支付,遇到些问题,以前做支付宝支付签名都是直接在客户端App进行,今天下了最新版本ios的支付宝支付demo,运行demo时底部有红色的显眼字体,告知用户签名必须在服务端进行... ...

  9. 如何有效快速提高Java服务端开发人员的技术水平?

    我相信很多工作了3-5年的开发人员都会经常问自己几个问题: 1.为什么总是感觉技术没有质的提高? 2.如何能够有效和快速的提高自身的技术水平? 3.如何进入到一个牛逼的大公司,认识牛逼的人? 这篇文章 ...

随机推荐

  1. css深入理解之 border

    一 border-width不支持百分比值 1 不符合客观逻辑 2 w3成都一种约定吧 3 边框本身就像是一个包裹内容的界限 类似的还有outline,box-shadow text-shadow均不 ...

  2. 【alpha】Scrum站立会议第3次....10.18

    小组名称:nice! 小组成员:李权 于淼 杨柳 刘芳芳 项目内容:约跑app(约吧--暂定) 1.任务进度 2.燃尽图 功能列表 1.登录注册 2.创建跑步计划 3.筛选跑友 4.加一起跑步的人为好 ...

  3. Vue脚手架开发使用sass

    vue默认采用的是原生的css,如果想要使用css预编译工具,比如sass,需要下载对应的scss的loader, 具体是 npm install --save-dev sass-loader npm ...

  4. (转)Linux NUMA引发的性能问题

    最近某客户的核心业务系统又出了翻译缓慢的情况.该问题在6月份也出现过,当时进行了一次调整. 我们首先来看下故障时间段的awr报告: 单纯的从TOP 5 event,基本上是看不出任何东西的,可能有人会 ...

  5. 安装多个版本JDK相关问题

    一.前言 因敝人计算器上面安装了多个版本的JDK,其中包括JDK1.6.JDK1.7.JDK1.8,想通过变换环境变量(JAVA_HOME)的形式切换不同的JDK,但是我在安装了JDK1.7并且配置了 ...

  6. Java中的多线程=你只要看这一篇就够了

    如果对什么是线程.什么是进程仍存有疑惑,请先Google之,因为这两个概念不在本文的范围之内. 用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现.说这个话其 ...

  7. BZOJ 1491 社交网络(最短路)

    对于这道题,如果我们能求出s到t的最短路径数目和s由v到t的最短路径数目,剩下的很好求了. 令dis[i][j]表示i到j的最短路径,dp[i][j]表示i到j的最短路径条数,如果dis[s][v]+ ...

  8. 【codevs1380】没有上司的舞会 树形dp

    题目描述 Ural大学有N个职员,编号为1~N.他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.每个职员有一个快乐指数.现在有个周年庆宴会,要求与会职员的快乐指数 ...

  9. BZOJ4832 抵制克苏恩(概率期望+动态规划)

    注意到A+B+C很小,容易想到设f[i][A][B][C]为第i次攻击后有A个血量为1.B个血量为2.C个血量为3的期望伤害,倒推暴力转移即可. #include<iostream> #i ...

  10. bzoj 1221: [HNOI2001] 软件开发 (网络流)

    注意说如果直接从每天的新的连向旧的,那整个图的最大流还是不变,答案就一直会是Σni*f type arr=record toward,next,cap,cost:longint; end; const ...