• 单例模式


    GOF中最简单的一个模式,只涉及到一个类。比如线程池、缓存等这些对象在应用只能被实例化一次,如果实例化多次,有可能会造成不可预测的后果。何谓单例?答曰:该类的对象只能被实例化一次。


    程序猿:如果只是为了让对象被创建一次,那我们直接把对象放在全局变量在不就可以解决这类问题了?
    大师:放在全局中的确可以解决该类问题,但还是存在一些缺陷。
    程序猿:什么缺陷?
    大师:你把对象放在全局变量中,意味着在程序启动的时候就必须要实例化,如果该对象创建的时间比较长而且
    在创建出来的时候不一定就用得上,那就会消耗资源,全局静态变量的确是能解决问题,但单例模式也一个不错
    的选择,你可以在需要的时候再创建它。

    单例模式实现



          类如何被实现化 :    new MyInstance(); 如果另一个对象想创建怎么办?当然还是可以通过new 来再一次进行创建。只要是公共类,就可以被重复创建。那如果不是公共类又是一种什么情况呢?只有同一个包中的类可以实例化它,但是也可以被多次实例化。
          如果有多年经验的你可能会想到 private MyInstance(),对了,如果应用私有构造函数,那就不能通过
    new来随心所欲的进行实例化了。那你可能又有一个问题要问了,不能通过new来实例化对象,那通过什么方式来实例化对象?来看一下下面的代码你就会晃然大悟了。

    1 public class MyInstance{
    2 
    3        private MyInstance(){
    4        }
    5        //
    6        public static MyInstance getMyInstance(){
    7               return new MyInstance();
    8        }
    9 }
    View Code

    通过getMyInstance方法,就可以进行实例化了,但这个跟直接跟通过new创建有何区别呢,代码还没有完成,我们来进一步完善

    public class MyInstance{
    
          private static MyInstance instance;
          //通过私有构造函数,防止用户通过默认的构造函数来实例化对象
          private MyInstance(){}  
          public static MyInstance getMyInstance(){
                 if(instance==null){
    System.out.print("myinstance is null"); instance
    =new MyInstance();
    }
    return instance; } }

    下面代码测试一下是否工作正常,建一个类来实例化MyInstance,然后在main中调用,

    1 public class Test {
    2     public void business(){
    3         MyInstance _instand1 = MyInstand.getMyInstance();
    4         MyInstance _instand2 = MyInstand.getMyInstance();
    5     }
    6 }
    View Code
    1 public class Main {
    2 
    3     public static void main(String[] args) {
    4          //TODO Auto-generated method stub
    5          Test t = new Test();
    6          t.business();
    7     }
    8 
    9 }
    View Code

    代码执行后,你会看到控制台只输出一条“Myinstance is null“,说明MyInstance只被实例化了一次。到此单例模式基本完成,为什么是基本完成而不是已完成了呢。要知详情请看后文。

    得意得太早


     现实永远比想象残酷,当你以为上面的代码已完成交给你的其他猿类使用时,末日来临了。请猿们看下面的代码,看看将会发生什么。

     1 public class Test extends Thread{
     2 
     3     @Override
     4     public void run() {
     5         // TODO Auto-generated method stub
     6               super.run();
     7                   MyInstance _instance = MyInstanece.getMyInstance();
     8     }
     9 }
    10 
    11 
    12 public class Main {
    13 
    14     /**
    15      * @param args
    16      */
    17     public static void main(String[] args) {
    18         // TODO Auto-generated method stub
    19          Test t1 = new Test();
    20          t1.start();
    21          Test t2 = new Test();
    22          t2.start();
    23     }
    24 
    25 }
    View Code

    执行以上代码发现了什么?出现了两条“myinstand is null”,你测试的没事,是出现两次,这就是线程做得手脚。

    解决


    既然是线程引起的,那我们就解决线程问题,在MyInstance的getMyInstance方法前加上“synchronized”,让线程同步,这种灾难将得到解决

     1 public class MyInstance {
     2     private static MyInstance _instance;
     3     private MyInstance(){}
     4     public static synchronized MyInstand getMyInstance(){
     5         if(_instance==null){
     6             System.out.print("myinstand is null");
     7             _instance =new MyInstance();
     8         }
     9         return _instance;
    10     }
    11 }
    View Code

    现在再执行代码,发现只实例化了一次。

    一波未平一波又起


    通过线程同步解决了上面出现的问题,但新的问题又出现在了我们的眼前,那就是程序的性能降低了。--未完待续

  • 相关阅读:
    Vmware虚拟机的单用户模式
    Xshell密钥认证
    PuTTY密钥认证
    CentOS 7在NAT模式下配置静态IP
    使用OllyDbg破解EasyCrackMe
    2017 计蒜之道 初赛 第五场 A. UCloud 机房的网络搭建
    2017 计蒜之道 初赛 第五场 A. UCloud 机房的网络搭建
    Kafka常用命令
    选择器和层叠
    语义化
  • 原文地址:https://www.cnblogs.com/sunrfun/p/3635211.html
Copyright © 2020-2023  润新知