array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 单例模式,你会写几种? - 爱码网
nedulee

定义:

  单例模式(singleton),保证一个类仅有一个实例,并且提供一个访问它的全局访问点。
  这句话很好理解,今天我们的重点也不在于如何解读单例模式。
  在面试的过程中,往往会遇到考察手写单例模式的场景,今天让我们关注一下,写单例模式的几种方法。

饿汉式:

/**
 * 饿汉式.
 *
 * @author jialin.li
 * @date 2019-12-30 22:13
 */
public class Singleton {
    private Singleton() {
    }

    private static Singleton singleton = new Singleton();

    public Singleton getInstance(){
        return singleton;
    }
}
    • 饿汉式的特点是类初始化的时候,创建了该对象。
    • 由于类只会初始化一次,所以保证了对象只会被创建一次。
    • 同时将构造方法私有化,保证了没有办法从外部创建对象。
  这种方法的问题是,如果该实例从始至终都没有被使用过,就会造成内存的浪费。

懒汉式:

/**
 * 懒汉式.
 *
 * @author jialin.li
 * @date 2019-12-30 22:13
 */
public class Singleton {
    private Singleton() {
    }

    private volatile Singleton singleton = null;

    public Singleton getInstance(){
        // 提高性能,降低线程进入临界区的可能
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
  这种写法又被成为双检锁模式,是一种实现单例模式的经典写法。
  代码中有两处判空:
    1. 第一处判空,是为了提高性能,降低线程进入临界区的可能性。
    2. 第二处判空是为了线程同步,假如没有第二处判空,则可能两个线程都通过了if(singleton==null)条件,这样即使是临界区内只有一个线程在执行,临界区内的代码也会被执行两遍,这样就会产生两个对象,不符合单例模式。
  成员变量使用了volatile进行修饰,一方面是保证了对象在多线程环境下的可见性,另一方面是为了防止new Singleton()进行指令重排序而导致的并发问题。
  volatile关键字的作用两个:
    1. 保证变量在线程之间的可见性(直接从主存中读写数据,不经过工作内存)
    2. 阻止编译时和运行时的指令重排,编译时JVM编译器遵循内存屏障约束,运行时依赖CPU屏障来阻止指令重排。
  指令重排是指JVM在编译Java代码的时候,或者CPU在执行JVM字节码的时候,对现有的指令顺序进行重新排序。
  指令重排的目的是为了在不改变程序执行结果的前提下,优化程序的运行效率。需要注意的是,这里所说的不改变执行结果,指的是不改变单线程下的程序执行结果。
这里不太好懂,举一个例子,正常的new Singleton()创建步骤是:
  1. 开辟一块内存空间
  2. 创建对象
  3. 将对象的地址存入引用变量
  经过指令重排后,可能变成了:
  1. 开辟一块内存空间
  2. 将对象的地址存入引用变量
  3. 创建对象

  假设发生了指令重排,线程A、B都执行这段代码,线程A执行到了new Singleton()的步骤2,此时还没有创建对象,这个时候发生了线程的切换。线程B开始执行,这个时候线程B还可以通过if(singleton == null)的判断,因为线程A中的singleton只是指向了一个空的内存地址,这个时候线程B创建出了一个Singleton对象,当线程切换成A时,线程A仍执行了new Singleton()的步骤3,此时创建了2个Singleton对象,不符合单例模式。

静态内部类单例模式:

/**
 * 静态内部类单例模式.
 *
 * @author jialin.li
 * @date 2019-12-30 22:13
 */
public class Singleton {
    private Singleton() {
    }

    public static Singleton getInstance() {
        return Inner.singleton;
    }

    private static class Inner {
        private static Singleton singleton = new Singleton();
    }
}
  这里利用的是内部类的特性,只有第一次调用getInstance方法的时候,虚拟机才会加载Inner并初始化singleton,并且只初始化一次。这种方法也是一种懒汉式的写法,只有在需要的时候,才创建对象。

枚举单例模式

  枚举类也是一种单例模式
public enum Singleton  {
    INSTANCE 
 
    //doSomething 该实例支持的行为
      
    //可以省略此方法,通过Singleton.INSTANCE进行操作
    public static Singleton get Instance() {
        return Singleton.INSTANCE;
    }
}
这种写法较为简单,并且没有办法用反射的方式,创建对象。但是可读性较差。

期待您的关注、推荐、收藏,同时也期待您的纠错和批评。

分类:

技术点:

相关文章: