Java多线程学习(四)

  1. 单例模式

    1.1立即加载/饿汉模式

    立即加载既为使用类的方法的时候已经将对象创建完毕。常见的实现方法就是直接new实例化。

    public class MyObject {
       private static MyObject myObject = new MyObject();
      private MyObject(){}
      public static MyObject getInstance(){
         return myObject;
      }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    运行结果为三个线程输出的值相同。

    1.2延迟加载/懒汉模式

    延迟加载既为调用类的方法时,对象实例才被创建。常见实现方法为在get方法中进行new实例化。

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
          if(myObject == null){ myObject = new MyObject();}
          return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    运行结果为三个线程输出的值不同,取出了多个线程实例,与单例模式相违背。

     

  2. 延迟加载的解决方案

    如上例所示的延迟加载方法,在多线程模式下是线程不安全的,那么就是以下几种解决方案吧!

    ①声明synchronized关键字

    既然出现线程不安全问题是因为多个线程同时进入getInstance方法导致的,那么就给这个方法上锁,同一时间内只有一个线程能够访问。

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       synchronized public static MyObject getInstance(){
          if(myObject == null){ 
               myObject = new MyObject();
          }
          return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    运行结果为三个线程输出的值相同。

    但是这种方法的运行效率非常低下。

    ②尝试同步代码块

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
             synchronized (MyObject.class){
                 if(myObject == null){ myObject = new MyObject();}
             }
             return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    运行结果为三个线程输出的值相同。

    但是这相当于第一种给方法上锁的方式,效率同样低下。

    ③尝试给重要代码上锁

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
             if(myObject == null){          
                   synchronized (MyObject.class){
                          myObject = new MyObject();
                   }
             }
             return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    运行结果为三个线程输出的值不相同,并不是单例的。

    这样的上锁方式虽然虽然提高了效率,但是仍有可能同时有多个线程进入if方法内部,等待执行同步代码块,因此获取了多个对象。

    ④使用DCL双检查锁机制

    public class MyObject {
       private static MyObject myObject;
       private MyObject(){}
       public static MyObject getInstance(){
             if(myObject == null){          
                   synchronized (MyObject.class){
                          if(myObject == null){
                                myObject = new MyObject();
                          }
                   }
             }
             return myObject;
       }
    }
    public class MyThread extends Thread {
        public void run(){
           System.out.println(MyObject.getInstance().hashCode());
       }
       
        public static void main(String [] args){
          MyThread t1 = new MyThread();
         MyThread t2 = new MyThread();
           MyThread t3 = new MyThread();
           
           t1.start();
           t2.start();
           t3.start();
       }
    }
    运行结果为三个线程输出的值相同。

    使用双重检查锁机制,成功的解决了懒汉模式遇到多线程的问题。DCL也是大多数多线程结合单例模式使用的解决方案。

你可能感兴趣的:(Java多线程学习(四))