标签分类
当前位置:首页 > 程序设计电子书 > java电子书网盘下载
大话JAVA性能优化 大话JAVA性能优化
qq54006162

qq54006162 提供上传

资源
36
粉丝
28
喜欢
129
评论
10

    大话JAVA性能优化 PDF 高清版

    java电子书
    • 发布时间:

    给大家带来的一篇关于java相关的电子书资源,介绍了关于JAVA性能、JAVA优化方面的内容,本书是由电子工业出版社出版,格式为PDF,资源大小116.9 MB,周明耀编写,目前豆瓣、亚马逊、当当、京东等电子书综合评分为:7.6,更多相关的学习资源可以参阅 程序设计电子书Java视频、等栏目。

  • 大话JAVA性能优化 PDF 下载
  • 下载地址:https://pan.baidu.com/s/1cLJ4uOMv0FXv0LedxNLpJA
  • 分享码:j6o5
  • 大话JAVA性能优化PDF

    《大话Java性能优化》关键出示Java性能调优层面的参照提议及经验总结。创作者务求保证专业知识的综合性散播,而并不是只是只对于Java虚拟机调优开展解读,另一个务求每个章节目录常有具体的实例支撑点。实际包含:性能优化对策、程序编程及硬件配置网络服务器的基本知识、JavaAPI优化提议、计算方法类程序流程的优化提议、并行计算优化提议、Java程序流程性能监控器及检验、JVM基本原理专业知识、别的有关优化专业知识等。

    细读《大话Java性能优化》后,用户能够 深层次掌握Java性能调优的很多主题风格及有关的综合型专业知识。用户还可以把《大话Java性能优化》做为参照,针对很感兴趣的主题风格,立即跳至相对章节目录找寻参考答案。

    综上所述,性能调优在挺大水平上是这门造型艺术,处理的Java性能难题越大,手艺才会越高超。人们不但要关注JVM的不断演变,还要积极主动地去掌握最底层的硬件平台和电脑操作系统的发展。

    目录

    • 第1章 性能调优策略概述 1
    • 第2章 优化前的准备知识 22
    • 第3章 Java API调用优化建议 54
    • 第4章 程序设计优化建议 176
    • 第5章 Java并行程序优化建议 270
    • 第6章 JVM性能测试及监控 377
    • 第7章 JVM性能调优建议 439
    • 第8章 其他优化建议 516
    • · · · · · ·

    读书笔记

    Java多线程优化方法及使用方式

    一、多线程介绍

    在编程中,我们不可逃避的会遇到多线程的编程问题,因为在大多数的业务系统中需要并发处理,如果是在并发的场景中,多线程就非常重要了。另外,我们在面试的时候,面试官通常也会问到我们关于多线程的问题,如:如何创建一个线程?我们通常会这么回答,主要有两种方法,第一种:继承Thread类,重写run方法;第二种:实现Runnable接口,重写run方法。那么面试官一定会问这两种方法各自的优缺点在哪,不管怎么样,我们会得出一个结论,那就是使用方式二,因为面向对象提倡少继承,尽量多用组合。

    这个时候,我们还可能想到,如果想得到多线程的返回值怎么办呢?根据我们多学到的知识,我们会想到实现Callable接口,重写call方法。那么多线程到底在实际项目中怎么使用呢,他有多少种方式呢?

    首先,我们来看一个例子:

    Java多线程优化方法及使用方式 

    这是一种创建多线程的简单方法,很容易理解,在例子中,根据不同的业务场景,我们可以在Thread()里边传入不同的参数实现不同的业务逻辑,但是,这个方法创建多线程暴漏出来的问题就是反复创建线程,而且创建线程后还得销毁,如果对并发场景要求低的情况下,这种方式貌似也可以,但是高并发的场景中,这种方式就不行了,因为创建线程销毁线程是非常耗资源的。所以根据经验,正确的做法是我们使用线程池技术,JDK提供了多种线程池类型供我们选择,具体方式可以查阅jdk的文档。

    Java多线程优化方法及使用方式 

    这里代码我们需要注意的是,传入的参数代表我们配置的线程数,是不是越多越好呢?肯定不是。因为我们在配置线程数的时候要充分考虑服务器的性能,线程配置的多,服务器的性能未必就优。通常,机器完成的计算是由线程数决定的,当线程数到达峰值,就无法在进行计算了。如果是耗CPU的业务逻辑(计算较多),线程数和核数一样就到达峰值了,如果是耗I/O的业务逻辑(操作数据库,文件上传、下载等),线程数越多一定意义上有助于提升性能。

    线程数大小的设定又一个公式决定:

    Y=N*((a+b)/a),其中,N:CPU核数,a:线程执行时程序的计算时间,b:线程执行时,程序的阻塞时间。有了这个公式后,线程池的线程数配置就会有约束了,我们可以根据机器的实际情况灵活配置。

    二、多线程优化及性能比较

    最近的项目中用到了所线程技术,在使用过程中遇到了很多的麻烦,趁着热度,整理一下几种多线程框架的性能比较。目前所掌握的大致分三种,第一种:ThreadPool(线程池)+CountDownLatch(程序计数器),第二种:Fork/Join框架,第三种JDK8并行流,下面对这几种方式的多线程处理性能做一下比较总结。

    首先,假设一种业务场景,在内存中生成多个文件对象,这里暂定30000,(Thread.sleep(时间))线程睡眠模拟业务处理业务逻辑,来比较这几种方式的多线程处理性能。

    1) 单线程

    这种方式非常简单,但是程序在处理的过程中非常的耗时,使用的时间会很长,因为每个线程都在等待当前线程执行完才会执行,和多线程没有多少关系,所以效率非常低。

    首先创建文件对象,代码如下:

    public class FileInfo {
     private String fileName;//文件名
     private String fileType;//文件类型
     private String fileSize;//文件大小
     private String fileMD5;//MD5码
     private String fileVersionNO;//文件版本号
     public FileInfo() {
      super();
     }
     public FileInfo(String fileName, String fileType, String fileSize, String fileMD5, String fileVersionNO) {
      super();
      this.fileName = fileName;
      this.fileType = fileType;
      this.fileSize = fileSize;
      this.fileMD5 = fileMD5;
      this.fileVersionNO = fileVersionNO;
     }
     public String getFileName() {
      return fileName;
     }
     public void setFileName(String fileName) {
      this.fileName = fileName;
     }
     public String getFileType() {
      return fileType;
     }
     public void setFileType(String fileType) {
      this.fileType = fileType;
     }
     public String getFileSize() {
      return fileSize;
     }
     public void setFileSize(String fileSize) {
      this.fileSize = fileSize;
     }
     public String getFileMD5() {
      return fileMD5;
     }
     public void setFileMD5(String fileMD5) {
      this.fileMD5 = fileMD5;
     }
     public String getFileVersionNO() {
      return fileVersionNO;
     }
     public void setFileVersionNO(String fileVersionNO) {
      this.fileVersionNO = fileVersionNO;
     }

    接着,模拟业务处理,创建30000个文件对象,线程睡眠1ms,之前设置的1000ms,发现时间很长,整个Eclipse卡掉了,所以将时间改为了1ms。

    public class Test {
       private static List<FileInfo> fileList= new ArrayList<FileInfo>();
       public static void main(String[] args) throws InterruptedException {
         createFileInfo();
         long startTime=System.currentTimeMillis();
         for(FileInfo fi:fileList){
           Thread.sleep(1);
         }
         long endTime=System.currentTimeMillis();
         System.out.println("单线程耗时:"+(endTime-startTime)+"ms");
       }
       private static void createFileInfo(){
         for(int i=0;i<30000;i++){
           fileList.add(new FileInfo("身份证正面照","jpg","101522","md5"+i,"1"));
         }
       }
    }

    测试结果如下:

    Java多线程优化方法及使用方式 

    可以看到,生成30000个文件对象消耗的时间比较长,接近1分钟,效率比较低。

    2) ThreadPool (线程池) +CountDownLatch (程序计数器)

    顾名思义,CountDownLatch为线程计数器,他的执行过程如下:首先,在主线程中调用await()方法,主线程阻塞,然后,将程序计数器作为参数传递给线程对象,最后,每个线程执行完任务后,调用countDown()方法表示完成任务。countDown()被执行多次后,主线程的await()会失效。实现过程如下:

    public class Test2 {
     private static ExecutorService executor=Executors.newFixedThreadPool(100);
     private static CountDownLatch countDownLatch=new CountDownLatch(100);
     private static List<FileInfo> fileList= new ArrayList<FileInfo>();
     private static List<List<FileInfo>> list=new ArrayList<>();
     public static void main(String[] args) throws InterruptedException {
      createFileInfo();
      addList();
      long startTime=System.currentTimeMillis();
      int i=0;
      for(List<FileInfo> fi:list){
       executor.submit(new FileRunnable(countDownLatch,fi,i));
       i++;
      }
      countDownLatch.await();
      long endTime=System.currentTimeMillis();
      executor.shutdown();
      System.out.println(i+"个线程耗时:"+(endTime-startTime)+"ms");
     }
     private static void createFileInfo(){
      for(int i=0;i<30000;i++){
       fileList.add(new FileInfo("身份证正面照","jpg","101522","md5"+i,"1"));
      }
     }
     private static void addList(){
      for(int i=0;i<100;i++){
       list.add(fileList);
      }
     }
    }

    FileRunnable类:

    /**
     * 多线程处理
     * @author wangsj
     *
     * @param <T>
     */
    public class FileRunnable<T> implements Runnable {
       private CountDownLatch countDownLatch;
       private List<T> list;
       private int i;
       public FileRunnable(CountDownLatch countDownLatch, List<T> list, int i) {
         super();
         this.countDownLatch = countDownLatch;
         this.list = list;
         this.i = i;
       }
       @Override
       public void run() {
         for(T t:list){
           try {
              Thread.sleep(1);
           } catch (InterruptedException e) {
              e.printStackTrace();
           }
           countDownLatch.countDown();
         }
       }
    }

    测试结果如下:

    Java多线程优化方法及使用方式 

    3) Fork/Join 框架

    Jdk从版本7开始,出现了Fork/join框架,从字面来理解,fork就是拆分,join就是合并,所以,该框架的思想就是。通过fork拆分任务,然后join来合并拆分后各个人物执行完毕后的结果并汇总。比如,我们要计算连续相加的几个数,2+4+5+7=?,我们利用Fork/join框架来怎么完成呢,思想就是拆分子任务,我们可以把这个运算拆分为两个子任务,一个计算2+4,另一个计算5+7,这是Fork的过程,计算完成后,把这两个子任务计算的结果汇总,得到总和,这是join的过程。

    Fork/Join框架执行思想:首先,分割任务,使用fork类将大任务分割为若干子任务,这个分割过程需要按照实际情况来定,直到分割出的任务足够小。然后,join类执行任务,分割的子任务在不同的队列里,几个线程分别从队列里获取任务并执行,执行完的结果放到一个单独的队列里,最后,启动线程,队列里拿取结果并合并结果。

    使用Fork/Join框架要用到几个类,关于类的使用方式可以参考JDK的API,使用该框架,首先需要继承ForkJoinTask类,通常,只需要继承他的子类RecursiveTask或RecursiveAction即可,RecursiveTask,用于有返回结果的场景,RecursiveAction用于没有返回结果的场景。ForkJoinTask的执行需要用到ForkJoinPool来执行,该类用于维护分割出的子任务添加到不同的任务队列。

    下面是实现代码:

    public class Test3 {
     private static List<FileInfo> fileList= new ArrayList<FileInfo>();
    // private static ForkJoinPool forkJoinPool=new ForkJoinPool(100);
    // private static Job<FileInfo> job=new Job<>(fileList.size()/100, fileList);
     public static void main(String[] args) {
      createFileInfo();
      long startTime=System.currentTimeMillis();
      ForkJoinPool forkJoinPool=new ForkJoinPool(100);
      //分割任务
      Job<FileInfo> job=new Job<>(fileList.size()/100, fileList);
      //提交任务返回结果
    ForkJoinTask<Integer> fjtResult=forkJoinPool.submit(job);
    //阻塞
      while(!job.isDone()){
       System.out.println("任务完成!");
      }
      long endTime=System.currentTimeMillis();
      System.out.println("fork/join框架耗时:"+(endTime-startTime)+"ms");
     }
     private static void createFileInfo(){
      for(int i=0;i<30000;i++){
       fileList.add(new FileInfo("身份证正面照","jpg","101522","md5"+i,"1"));
      }
     }
    }
    /**
     * 执行任务类
     * @author wangsj
     *
     */
    public class Job<T> extends RecursiveTask<Integer> {
     private static final long serialVersionUID = 1L;
     private int count;
     private List<T> jobList;
     public Job(int count, List<T> jobList) {
      super();
      this.count = count;
      this.jobList = jobList;
     }
     /**
      * 执行任务,类似于实现Runnable接口的run方法
      */
     @Override
     protected Integer compute() {
      //拆分任务
      if(jobList.size()<=count){
       executeJob();
       return jobList.size();
      }else{
       //继续创建任务,直到能够分解执行
       List<RecursiveTask<Long>> fork = new LinkedList<RecursiveTask<Long>>();
       //拆分子任务,这里采用二分法
       int countJob=jobList.size()/2;
       List<T> leftList=jobList.subList(0, countJob);
       List<T> rightList=jobList.subList(countJob, jobList.size());
       //分配任务
       Job leftJob=new Job<>(count,leftList);
       Job rightJob=new Job<>(count,rightList);
       //执行任务
       leftJob.fork();
       rightJob.fork();
       return Integer.parseInt(leftJob.join().toString())
         +Integer.parseInt(rightJob.join().toString());
      }
     }
     /**
      * 执行任务方法
      */
     private void executeJob() {
      for(T job:jobList){
       try {
        Thread.sleep(1);
       } catch (InterruptedException e) {
        e.printStackTrace();
       }
      }
     }

    测试结果如下:

    Java多线程优化方法及使用方式 

    4) JDK8 并行流

    并行流是jdk8的新特性之一,思想就是将一个顺序执行的流变为一个并发的流,通过调用parallel()方法来实现。并行流将一个流分成多个数据块,用不同的线程来处理不同的数据块的流,最后合并每个块数据流的处理结果,类似于Fork/Join框架。

    并行流默认使用的是公共线程池ForkJoinPool,他的线程数是使用的默认值,根据机器的核数,我们可以适当调整线程数的大小。线程数的调整通过以下方式来实现。

    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "100");

    以下是代码的实现过程,非常简单:

    public class Test4 {
    private static List<FileInfo> fileList= new ArrayList<FileInfo>();
    public static void main(String[] args) {
    //    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "100");
       createFileInfo();
       long startTime=System.currentTimeMillis();
       fileList.parallelStream().forEach(e ->{
         try {
            Thread.sleep(1);
         } catch (InterruptedException f) {
            f.printStackTrace();
         }
       });
       long endTime=System.currentTimeMillis();
       System.out.println("jdk8并行流耗时:"+(endTime-startTime)+"ms");
    }
    private static void createFileInfo(){
       for(int i=0;i<30000;i++){
         fileList.add(new FileInfo("身份证正面照","jpg","101522","md5"+i,"1"));
       }
    }
    }

    下面是测试,第一次没有设置线程池的数量,采用默认,测试结果如下:

    Java多线程优化方法及使用方式 

    我们看到,结果并不是很理想,耗时较长,接下来设置线程池的数量大小,即添加如下代码:

    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "100");

    接着进行测试,结果如下:

    Java多线程优化方法及使用方式 

    这次耗时较小,比较理想。

    三、总结

    综上几种情况来看,以单线程作为参考,耗时最长的还是原生的Fork/Join框架,这里边尽管配置了线程池的数量,但效果较精确配置了线程池数量的JDK8并行流较差。并行流实现代码简单易懂,不需要我们写多余的for循环,一个parallelStream方法全部搞定,代码量大大的减少了,其实,并行流的底层还是使用的Fork/Join框架,这就要求我们在开发的过程中灵活使用各种技术,分清各种技术的优缺点,从而能够更好的为我们服务。

    上一篇:人工智能时代  下一篇:写给PHP开发者的Node.js学习指南

    展开 +

    收起 -

    java相关电子书
    学习笔记
    网友NO.475759

    基于JavaScript 性能优化技巧心得(分享)

    JavaScript 作为当前最为常见的直译式脚本语言,已经广泛应用于 Web 应用开发中。为了提高Web应用的性能,从 JavaScript 的性能优化方向入手,会是一个很好的选择。 本文从加载、上下文、解析、编译、执行和捆绑等多个方面来讲解 JavaScript 的性能优化技巧,以便让更多的前端开发人员掌握这方面知识。 什么是高性能的 JavaScript 代码? 尽管目前没有高性能代码的绝对定义,但却存在一个以用户为中心的性能模型,可以用作参考:RAIL模型。 响应 如果你的应用程序能在100毫秒内响应用户的操作,那么用户会认为该响应为即时的。这适用于可点击的元素,不适用于滚动或拖动操作。 动画 在60Hz的显示器上,我们希望动画和滚动时每秒有60帧,这种情况下每帧大约为16ms。在这16ms的时间内,实际上只有8-10ms来完成所有工作,其余时间则由浏览器的内部和其它差异占据。 空闲工作 如果你有一个耗时很久,需要持续运行的任务时,请确保把它分成很小的块,以便允许主线程对用户的输入操作做出反应。不应该出现一个任务延迟超过50ms的用户输入。 加载 页面加载应该在1000毫秒内完成。在移动设备上,这是一个很难达到的目标,因为它涉及到页面的互动,而不仅仅是在屏幕上渲染和滚动。 现代加载最佳实践(Chrome Dev Summit 2017) 如果……

    网友NO.721441

    浅析JavaScript异步代码优化

    前言 在实际编码中,我们经常会遇到Javascript代码异步执行的场景,比如ajax的调用、定时器的使用等,在这样的场景下也经常会出现这样那样匪夷所思的bug或者糟糕的代码片段,那么处理好你的Javascript异步代码成为了异步编程至关重要的前提。下面我们从问题出发,一步步完善你的异步代码。 异步问题 1. 回调地狱 首先,我们来看下异步编程中最常见的一种问题,便是回调地狱。它的出现是由于异步代码执行时间的不确定性及代码间的依赖关系引发的,比如: // 一个动画结束后,执行下一个动画,下一个动画结束后再执行下一个动画$('#box').animate({width: '100px'}, 1000, function(){ $('#box').animate({height: '100px'}, 1000, function(){ $('#box').animate({left: 100}, 1000); });}); 由于我们不知道第一个动画什么时候开始或者什么时候结束,所以我们把第二个动画的执行内容放到了第一个动画的结束事件里,把第三个动画放到了第二个动画的结束事件里,这时候如果有很多这样的动画,那么就会形成回调地狱。 2. 捕获异常 除了回调地狱,如果我们需要在异步代码中捕获异常也比较麻烦,可能需要手动配置捕获方法: try { throw new Error('fail');} catch (e) { console.log(e);} 这样的代码书写明显不是我们想要的,不仅不利于维护,而且也在一定程度上违背了良好的J……

    网友NO.436758

    JAVA下单接口优化实战TPS性能提高10倍

    概述 最近公司的下单接口有些慢,老板担心无法支撑双11,想让我优化一把,但是前提是不允许大改,因为下单接口太复杂了,如果改动太大,怕有风险。另外开发成本和测试成本也非常大。对于这种有挑战性的任务,我向来是非常喜欢的,因为在解决问题的过程中,可以学习到很多东西。 当时我只是知道下单接口慢,但是没人告诉我慢在哪里,也即是说,哪些瓶颈导致下单接口慢了。其实没人知道也没关系的,因为我们可以通过压测来找到具体的瓶颈。 下面会详细介绍一下,在本次压测中遇到的问题以及如何解决,期间用了什么工具。 用到的工具和环境 工具 Jmeter JAVA自带的jvisualvm JMX nmon 环境 腾讯云Mysql 腾讯云2核4g的服务器1台 找瓶颈 下单属于写接口,大部分情况下,瓶颈都出在 DB 里,程序可能都在等待 DB 锁的释放。为了验证这个想法,我们可以使用 Jmeter 和 jvisualvm 来验证一下。 为了监控服务器和服务器中JAVA进程,我们需要开启JMX,可以在JAVA进程启动的时候,添加如下几个参数: JMX_OPTS="-Dcom.sun.management.jmxremote.port=7969 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=xx.xx.xx.xx"nohup java ${JMX_OPTS} -jar xxxxx.jar Djava.rmi.server.hostname 填写 JAVA 进程所在服务器的……

    Copyright 2018-2019 xz577.com 码农之家

    版权责任说明