N scene singleton N kinds wording

Which includes the cliché starving formula, formula and lazy enumeration class static scene serialization code block, multi-threading scenario in question.

Man of few words said, directly open to dry.
Hungry man style is immediately loaded meaning, immediately loaded with anxious, urgent meaning in Chinese. So called hungry Chinese-style bar.
1. The most simple version of a hungry man style

package 单例模式的几种写法.饿汉式;

/**
 * @Author:FuYouJie
 * @Date Create in 2020/1/23 13:32
 */
public class Singleton1 {
    /**饿汉式:直接创建实例 不管你是否需要
     * 1.构造器私有化 外部不能直接new实例化
     * 2.自行创建 并且用静态变量保存
     * 3.声明为public 对外公开这个实例
     * 4.final 修饰
     * 构造器 私有化
     */
    public static final Singleton1 instance=new Singleton1();
    private Singleton1(){}

}

Test code:

Singleton1 singleton1 = Singleton1.instance;
        Singleton1 s=Singleton1.instance;
        //true
        System.out.println(singleton1==s);

Here it is not the first map, the result is the same, ha. == Here is a comparison of the object address.
2. The wording simple enumeration class

public enum  SingletonByEnum {
    INSTANCE;
    public void doA(){
        System.out.println("AA");
    }
}

Test code:

//枚举
        SingletonByEnum instance1 = SingletonByEnum.INSTANCE;
        SingletonByEnum instance2 = SingletonByEnum.INSTANCE;
        //true
        System.out.println(instance1.hashCode()==instance2.hashCode());

3. static code blocks written:

public class SingletonStatic {
    public static final SingletonStatic INSTANCE;
    private String name;
    static {
        Properties properties=new Properties();
        try {
            properties.load(SingletonStatic.class.getClassLoader().getResourceAsStream("single.properties"));
        } catch (IOException e) {
            throw  new RuntimeException();
        }
        INSTANCE = new SingletonStatic(properties.getProperty("name"));
    }
    //构造器 私有化
    private SingletonStatic(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }
    
}

Here's static code block enables the properties to be copied from the profile function, to avoid the situation in which the properties of the code written death.
External configuration file
Here Insert Picture Description
Summary: Hungry Han style is space for time, the way the class loader is loaded on demand, and loaded only once. Thus, in the above embodiment a single class is loaded, it will instantiate an object and a reference to its own, for system use. In other words, before the thread access singleton object has been created. Plus, since one class throughout the life cycle will only be loaded once, this will only create a singleton class instance, that is to say, each thread can only be bound only can get this unique object. Therefore say, a hungry man single cases inherently thread-safe.

But often we say lazy to change the world, then we must have a lazy man. Did not change the world I do not know, at least changed my words.
Lazy man also said delay loading, is just to create an instance when calling the get method.
1. lazy man's simple version:

//Unsafe
public class Singleton1 {
    private static Singleton1 INSTANCE;
    public static Singleton1 getInstance(){
        if (INSTANCE==null){
            try {
            //模拟准备时间
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE=new Singleton1();
        }
        return INSTANCE;
    }
    private Singleton1(){}

}

== == Under single-threaded, this code is not a problem.
Test code:

//单线程下
        Singleton1 singleton1=Singleton1.getInstance();
        Singleton1 singleton2=Singleton1.getInstance();
        System.out.println(singleton1==singleton2);

The result:
Under single-threaded operating results
you can see that the object is the same.
If it is multi-threaded?

First we create can receive a return value of Callable

Callable<Singleton1> callable=new Callable<Singleton1>() {
            @Override
            public Singleton1 call() throws Exception {
                return Singleton1.getInstance();
            }
        };

Then create a thread pool (as Ali Mama plug-in installed, the screen directly create a thread yellow).

ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(2,
                2,1,
                TimeUnit.MINUTES,new LinkedBlockingQueue<>(5),
                new ThreadPoolExecutor.CallerRunsPolicy());

Then submit again to receive Future

Future<Singleton1> singleton1Future = threadPoolExecutor.submit(callable);
Future<Singleton1> singleton2Future = threadPoolExecutor.submit(callable);

Finally, take the results

try {
            //false
            System.out.println(singleton1Future.get().hashCode()==singleton2Future.get().hashCode());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        threadPoolExecutor.shutdown();

The result:
Here Insert Picture Description
So this is why it?
When the thread 1 into, the object does not exist at this time, experiencing sleep (1000), Thread 1 begins one second left standing.
Here Insert Picture Description
When left standing thread 1, thread 2 also came in. Together they have just left standing in a position, in which case a second not in the past, the object still does not exist.
Thread 1 then left standing end, enter the code behind, new object. Shortly after, the thread 2 to the back, and this time there is no non-empty judgment, so the thread 2 creates an object.
Solution lock . Here on the use of synchronized
lazy approach lock version:

public class SingletonWithSynMethod {
    private static SingletonWithSynMethod INSTANCE;
    public synchronized static SingletonWithSynMethod getInstance(){
        if (INSTANCE==null){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE=new SingletonWithSynMethod();
        }
        return INSTANCE;
    }
    private SingletonWithSynMethod(){}
}

have a test:

 class TestSingletonWithSynMethod{
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(2,
                2,1,
                TimeUnit.MINUTES,new LinkedBlockingQueue<>(5),
                new ThreadPoolExecutor.CallerRunsPolicy());
        Callable<SingletonWithSynMethod>singleton1=new Callable<SingletonWithSynMethod>() {
            @Override
            public SingletonWithSynMethod call() throws Exception {
                return SingletonWithSynMethod.getInstance();
            }
        };
    Future<SingletonWithSynMethod> future1= threadPoolExecutor.submit(singleton1);
    Future<SingletonWithSynMethod> future2= threadPoolExecutor.submit(singleton1);
        try {
            //true
            System.out.println(future1.get()==future2.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        threadPoolExecutor.shutdown();

    }
}

Here Insert Picture Description
But the spirit does not mean locking block lock method, we can change about the location of synchronized.

public class SingletonWithSynBlock {
    private static SingletonWithSynBlock INSTANCE;
    public  static SingletonWithSynBlock getInstance(){
        if (INSTANCE==null){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (SingletonWithSynBlock.class){
                INSTANCE=new SingletonWithSynBlock();
            }
        }
        return INSTANCE;
    }
    private SingletonWithSynBlock(){}
}

Do you think this get away?
We run it.
Run the code:

class TestSingletonWithSynBlock{
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(2,
                2,1,
                TimeUnit.MINUTES,new LinkedBlockingQueue<>(5),
                new ThreadPoolExecutor.CallerRunsPolicy());
        Callable<SingletonWithSynBlock> singleton1=new Callable<SingletonWithSynBlock>() {
            @Override
            public SingletonWithSynBlock call() throws Exception {
                return SingletonWithSynBlock.getInstance();
            }
        };
        Future<SingletonWithSynBlock> future1= threadPoolExecutor.submit(singleton1);
        Future<SingletonWithSynBlock> future2=  threadPoolExecutor.submit(singleton1);
        try {
            //false
            System.out.println(future1.get()==future2.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        threadPoolExecutor.shutdown();
    }
}

Here Insert Picture Description
So we introduce DCL double checking mechanism
Code:

public class SingletonWithDCL {
    private volatile static SingletonWithDCL INSTANCE;
    public static SingletonWithDCL getInstance(){
        try {
            if (INSTANCE != null){
            }else {
                Thread.sleep(3000);
                synchronized (SingletonWithDCL.class){
                    if (INSTANCE == null){
                        INSTANCE=new SingletonWithDCL();
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return INSTANCE;
    }
    private SingletonWithDCL(){}
}

Test code:

class TestSingletonWithDCL{
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(2,
                2,1,
                TimeUnit.MINUTES,new LinkedBlockingQueue<>(5),
                new ThreadPoolExecutor.CallerRunsPolicy());
        Callable<SingletonWithDCL> singleton1=new Callable<SingletonWithDCL>() {
            @Override
            public SingletonWithDCL call() throws Exception {
                return SingletonWithDCL.getInstance();
            }
        };
        Future<SingletonWithDCL> future1= threadPoolExecutor.submit(singleton1);
        Future<SingletonWithDCL> future2=   threadPoolExecutor.submit(singleton1);
        try {
            //true
            System.out.println(future1.get()==future2.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Run:
Here Insert Picture Description
Here Insert Picture Description
lazy mode also can be used inside the class

public class SingletonWithInner {
    /**
     * 内部类不会随着外部类的加载初始化
     */
    private static class MyClassHandler{
        private static SingletonWithInner INSTANCE=new SingletonWithInner();
    }
    public static SingletonWithInner getInstance(){
        return MyClassHandler.INSTANCE;
    }
    private SingletonWithInner(){}

}

But no such cheap, inner classes there will be problems in the sequence of the time.
Rewrite inner class

public class SingletonAndSer implements Serializable {
    private static final long serialVersionUID=888L;
    //内部类
    private static class MyClassHandler{
        private static final SingletonAndSer INSTANCE=new SingletonAndSer();
    }
    private SingletonAndSer(){}
    public static SingletonAndSer getInstance(){
        return MyClassHandler.INSTANCE;
    }
//  protected Object readResolve() throws ObjectStreamException{
//      System.out.println("调用了本方法!");
//      return MyClassHandler.INSTANCE;
//  }
}

Test categories:

class SaveAndRead{
    public static void main(String[] args) {
            SingletonAndSer singletonAndSer=SingletonAndSer.getInstance();
            try {
            FileOutputStream fosRef=new FileOutputStream(new File("test.txt"));
            ObjectOutputStream oosRef=new ObjectOutputStream(fosRef);
            oosRef.writeObject(singletonAndSer);
            oosRef.close();
            fosRef.close();
            System.out.println(singletonAndSer.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }


        try {
            FileInputStream fileInputStream=new FileInputStream(new File("test.txt"));
            ObjectInputStream objectInputStream=new ObjectInputStream(fileInputStream);
            SingletonAndSer singletonAndSer1= (SingletonAndSer) objectInputStream.readObject();
            objectInputStream.close();
            fileInputStream.close();


            System.out.println(singletonAndSer1.hashCode());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

Run:
Here Insert Picture Description
Nani? ?
If no readResolve it is still more cases in the deserialization time.
The solution is to remove the comment.
Add readResolve method.

protected Object readResolve() throws ObjectStreamException{
        System.out.println("调用了本方法!");
        return MyClassHandler.INSTANCE;
    }

Run:
Here Insert Picture Description
Well, here it is almost over now. But the enumeration class most directly exposed to the start of the violation of the "single responsibility principle", now to perfect perfection.
Connection to an example.

/**
 * @Author:FuYouJie
 * @Date Create in 2020/1/23 16:40
 */
public class Connection {
    String url;
    String name;

    public Connection(String url, String name) {
        this.url = url;
        this.name = name;
    }
}
public class MyObject {
    public enum MyEnumSinggleton{
        //工厂
        connectionFactory;
        private Connection connection;
        private MyEnumSinggleton(){
                System.out.println("创建MyObject");
                String url="jdbc:mysql://127.0.0.1:3306/bookdb?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false";
                String username="root";
                connection=new Connection(url,username);
        }
        public Connection getConnection(){
            return connection;
        }
    }
    public static Connection getConnection(){
        return MyEnumSinggleton.connectionFactory.getConnection();
    }

}

Test code:

class TestMyObject{
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(5,
                5,1,
                TimeUnit.MINUTES,new LinkedBlockingQueue<>(5),
                new ThreadPoolExecutor.CallerRunsPolicy());
        Callable<Connection> singleton1=new Callable<Connection>() {
            @Override
            public Connection call() throws Exception {
                return MyObject.getConnection();
            }
        };
        for(int i=0;i<5;i++){
            Future<Connection> future= threadPoolExecutor.submit(singleton1);
            System.out.println(future.get());
        }
        threadPoolExecutor.shutdown();
    }
}

Run:
Here Insert Picture Description
Go ahead, tired. It micro-channel qazwsxFuYouJie
throw bricks can add micro-channel.
GitHub code address: JaveSE knowledge

Guess you like

Origin www.cnblogs.com/FuYouJ/p/12230931.html