Java性能调优实战
刘超
金山软件西山居技术经理
立即订阅
7535 人已学习
课程目录
已完结 48 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样才能做好性能调优?
免费
模块一 · 概述 (2讲)
01 | 如何制定性能调优标准?
02 | 如何制定性能调优策略?
模块二 · Java编程性能调优 (10讲)
03 | 字符串性能优化不容小觑,百M内存轻松存储几十G数据
04 | 慎重使用正则表达式
05 | ArrayList还是LinkedList?使用不当性能差千倍
加餐 | 推荐几款常用的性能测试工具
06 | Stream如何提高遍历集合效率?
07 | 深入浅出HashMap的设计与优化
08 | 网络通信优化之I/O模型:如何解决高并发下I/O瓶颈?
09 | 网络通信优化之序列化:避免使用Java序列化
10 | 网络通信优化之通信协议:如何优化RPC网络通信?
11 | 答疑课堂:深入了解NIO的优化实现原理
模块三 · 多线程性能调优 (10讲)
12 | 多线程之锁优化(上):深入了解Synchronized同步锁的优化方法
13 | 多线程之锁优化(中):深入了解Lock同步锁的优化方法
14 | 多线程之锁优化(下):使用乐观锁优化并行操作
15 | 多线程调优(上):哪些操作导致了上下文切换?
16 | 多线程调优(下):如何优化多线程上下文切换?
17 | 并发容器的使用:识别不同场景下最优容器
18 | 如何设置线程池大小?
19 | 如何用协程来优化多线程业务?
20 | 答疑课堂:模块三热点问题解答
加餐 | 什么是数据的强、弱一致性?
模块四 · JVM性能监测及调优 (6讲)
21 | 磨刀不误砍柴工:欲知JVM调优先了解JVM内存模型
22 | 深入JVM即时编译器JIT,优化Java编译
23 | 如何优化垃圾回收机制?
24 | 如何优化JVM内存分配?
25 | 内存持续上升,我该如何排查问题?
26 | 答疑课堂:模块四热点问题解答
模块五 · 设计模式调优 (6讲)
27 | 单例模式:如何创建单一对象优化系统性能?
28 | 原型模式与享元模式:提升系统性能的利器
29 | 如何使用设计模式优化并发编程?
30 | 生产者消费者模式:电商库存设计优化
31 | 装饰器模式:如何优化电商系统中复杂的商品价格策略?
32 | 答疑课堂:模块五思考题集锦
模块六 · 数据库性能调优 (8讲)
33 | MySQL调优之SQL语句:如何写出高性能SQL语句?
34 | MySQL调优之事务:高并发场景下的数据库事务调优
35 | MySQL调优之索引:索引的失效与优化
36 | 记一次线上SQL死锁事故:如何避免死锁?
37 | 什么时候需要分表分库?
38 | 电商系统表设计优化案例分析
39 | 数据库参数设置优化,失之毫厘差之千里
40 | 答疑课堂:MySQL中InnoDB的知识点串讲
模块七 · 实战演练场 (4讲)
41 | 如何设计更优的分布式锁?
42 | 电商系统的分布式事务调优
43 | 如何使用缓存优化系统性能?
44 | 记一次双十一抢购性能瓶颈调优
结束语 (1讲)
结束语 | 栉风沐雨,砥砺前行!
Java性能调优实战
登录|注册

32 | 答疑课堂:模块五思考题集锦

刘超 2019-08-03
你好,我是刘超。
模块五我们都在讨论设计模式,在我看来,设计模式不仅可以优化我们的代码结构,使代码可扩展性、可读性强,同时也起到了优化系统性能的作用,这是我设置这个模块的初衷。特别是在一些高并发场景中,线程协作相关的设计模式可以大大提高程序的运行性能。
那么截至本周,有关设计模式的内容就结束了,不知你有没有发现这个模块的思考题都比较发散,很多同学也在留言区中写出了很多硬核信息,促进了技术交流。这一讲的答疑课堂我就来为你总结下课后思考题,希望我的答案能让你有新的收获。
除了以上那些实现单例的方式,你还知道其它实现方式吗?
第 9 讲中,我曾提到过一个单例序列化问题,其答案就是使用枚举来实现单例,这样可以避免 Java 序列化破坏一个类的单例。
枚举生来就是单例,枚举类的域(field)其实是相应的 enum 类型的一个实例对象,因为在 Java 中枚举是一种语法糖,所以在编译后,枚举类中的枚举域会被声明为 static 属性。
第 26 讲中,我已经详细解释了 JVM 是如何保证 static 成员变量只被实例化一次的,我们不妨再来回顾下。使用了 static 修饰的成员变量,会在类初始化的过程中被收集进类构造器即 <clinit> 方法中,在多线程场景下,JVM 会保证只有一个线程能执行该类的 <clinit> 方法,其它线程将会被阻塞等待。等到唯一的一次 <clinit> 方法执行完成,其它线程将不会再执行 <clinit> 方法,转而执行自己的代码。也就是说,static 修饰了成员变量,在多线程的情况下能保证只实例化一次。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Java性能调优实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(13)

  • 发条橙子 。
    老师, 对于单例模式那块还是有些不解,希望老师解答 :😄

    在类初始化时 会将 static成员变量放到 <clinit> 方法中 ,在类加载准备阶段负责为其创建内存,到了初始化阶段执行<clinit >方法 进行赋值。

    1. 请问在类加载的时候也会存在多线程的场景么?这块不太好理解 。以及后面改成了创建一个内部类, 在类加载的时候内部类应该会一起被加载 ,这时候内部类中的static也会一起被赋值,和直接在外层的类中直接初始化有什么区别么 ?

    2. 老师,另外有个点想确认下, 类的字面量(字符串和final修饰的成员变量)会在类加载的时候被放到堆的永久代中(运行时常量池)。那 static修饰的成员变量还是放在元数据空间里是么

    作者回复: 1、外部类初次加载,会初始化静态变量、静态代码块、静态方法,但不会加载内部类和静态内部类。

    如果我们使用内部类实现,不会在初始化类时加载内部类,只有在我们第一次调用EnumSingleton.INSTANCE,才会加载 EnumSingleton 类,而只有在加载EnumSingleton类之后,才会实例化创建INSTANCE对象,由于INSTANCE是一个静态成员变量,所以在初始化时由<clinit> 方法保证线程安全。

    2、元空间存放的是类元素,而静态常量池存放的是类的字面量和字符引用,运行时常量池存放的是直接引用。这里的静态常量池也是很多人说的字符串常量池。

    2019-08-03
    5
  • Jxin
    打卡,转眼已过大半,感谢老师一致以来的分享。棒棒的。

    作者回复: 同样感谢你们一路以来的坚持和支持。

    2019-08-03
    3
  • 疯狂咸鱼
    老师会讲数据库调优么?

    作者回复: 下一讲开始讲到数据库调优了,欢迎一起学习成长。

    2019-08-03
    2
  • 失火的夏天
    老师我问一下,内部类和静态内部类的区别是什么,哪里有不同,我看jdk里map的node,还有list的node都是静态的。之前有看到设置成静态是为了防止内存泄露,但是没有想明白是为什么

    作者回复: 我理解的是,静态内部类是一个独立类,只是借用外部类来隐藏自己。跟外部类没有实质性的关系,即内部静态类不需要有指向外部类的引用。 map的node以及list的node都是一个独立类,不属于map和list,但node又想借外部类来存放自己。这种方式也可以防止内存泄漏。

    而内部类则不一样,内部类只能在外部类中实例化被使用,属于真正的内部类,属于外部类的一部分,它可以访问外部类的任何成员变量。非静态内部类需要持有对外部类的引用。

    2019-08-03
    1
    1
  • 风轻扬
    老师,您在枚举单例的例子。
    // 懒汉模式 枚举实现
    public class Singleton {
        INSTANCE;// 不实例化
        public List<String> list = null;// list 属性

    private Singleton(){// 构造函数
    list = new ArrayList<String>();
    }
        // 使用枚举作为内部类
        private enum EnumSingleton {
            INSTANCE;// 不实例化
            private Singleton instance = null;

            private EnumSingleton(){// 构造函数
    instance = new Singleton();
          }
            public static Singleton getSingleton(){
                return instance;// 返回已存在的对象
            }
        }

        public static Singleton getInstance(){
            return EnumSingleton.INSTANCE.getSingleton();// 返回已存在的对象
        }
    }
    问:
    枚举类的getSingleton方法不能用static修饰吧?
    Singleton字段没有被static修饰,getSingleton方法应该引用不到Singlton字段啊?
    编译过不去

    作者回复: 对的,不用使用static修饰

    2019-09-19
  • 风轻扬
    老师,Future设计模式。我自己画了一下类图。感觉这完全是在模拟线程池的submit(Callable callable)的模式啊。我们直接用java的ThreadPoolExcutor。将Per-Thread模式中的任务类,实现Callable接口,然后使用ThreadPoolExcutor.submit(任务类),然后拿到Future,调用它的get方法就行了。干嘛要自己设计呢?

    作者回复: 通过动手实现,更透彻的理解Future的实现原理

    2019-09-19
    1
  • godtrue
    本节值得反复看,很不错的经验分享。
    2019-09-13
  • suncar
    老师,请教一个问题。如果在服务器上部署两个应用。是不是JDK应该对应一个应用。单独对 jvm进行优化。我觉得这样的部署话 JVM参数配置相互不影响,性能比较高。不知到这样是否合理?请老师给点建议

    作者回复: 这相当于两个JVM,设置的参数是互不影响的。但是还是会存在相互影响的情况,会存在相互竞争一些共享资源的情况,例如CPU,IO等

    2019-08-09
    1
  • Liam
    单例应该作为枚举类型的一个属性,在私有构造方法内创建并初始化,暴露一个获取方法,通过枚举实例去获取单例时会触发单例初始化,这里是否有必要区分懒汉恶汉?谈话关注点不应该在枚举实例上吧

    作者回复: 枚举类的域,即代码中的INSTANCE就是我们已经实例化对象的属性了,相当于private static Singleton instance=new Singleton()。 正常的枚举实现是一个饿汉模式,没有懒加载的实现。枚举类的这个可以再仔细思考下。

    2019-08-06
  • Liam
    枚举单例这里没看懂,单例不应该是作为枚举类的一个属性,然后在枚举的私有构造方法内实力化

    作者回复: 枚举是饿汉模式,也就是在属性中已经实例化了,相当于我们最开始讲的饿汉模式。

    2019-08-06
  • 晓杰
    老师,枚举单例的懒汉模式写的有问题吧

    作者回复: 具体哪里有问题呢?欢迎指出

    2019-08-05
  • -W.LI-
    老师好!感觉自己写代码很多时候都是面向过程的思维。纯纯的CRUD程序员平时99%的工作都是增删改查+处理业务逻辑。如何培养自己的面向对象思维?老师有好的建议书籍推荐么?万分感谢,我感觉这个应该是共性的问题。

    作者回复: 需要自己在工作中多学会思考,再加上多读一些源码,对着源码自己再重新手写这套设计模式的实现。我在之前推荐过《大话设计模式》这本书,写的比较生动有趣,建议阅读。

    2019-08-03
  • -W.LI-
    很干货谢谢老师。future那个感觉很不错,之前都是用的future+线程池+countdownLanch。实现回调的,调用get方法的时候确实会阻塞等待最后一个任务完成为止,如果需要对一批任务做组合处理的化只能这样了吧。如果不需要聚合处理就可以使用CompletableFuture进行优化,回头看下CompletableFuture。之前好像看过future类的源码,没记错的话和老师的代码实现一样,依稀记得只是包了一层,future的run方法里面调用任务的callable方法,返回值存放在future的成员变量result里。future这个算代理模式么?

    作者回复: 更像观察者模式

    2019-08-03
收起评论
13
返回
顶部