From 0e5bad0fc462fbd0ef321959cc737f36ccd4cbaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=E5=98=89=E9=98=B3?= Date: Tue, 25 Sep 2018 16:21:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=B9=E5=99=A8=EF=BC=88=E9=9B=86=E5=90=88?= =?UTF-8?q?=EF=BC=89=E5=AE=9E=E7=8E=B0=E5=8D=95=E4=BE=8B=EF=BC=8C=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=BA=BF=E7=A8=8B=E5=AE=89=E5=85=A8=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 ++ .../singleton/ContainerSingleton.java | 50 ++++++++++++ .../ContainerSingletonHashtable.java | 50 ++++++++++++ .../singleton/ContainerSingletonTest.java | 79 +++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingleton.java create mode 100644 src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonHashtable.java create mode 100644 src/test/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonTest.java diff --git a/pom.xml b/pom.xml index d6dc414..9cb920c 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,13 @@ 2.11.0 + + + org.apache.commons + commons-lang3 + 3.8.1 + + diff --git a/src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingleton.java b/src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingleton.java new file mode 100644 index 0000000..8ea79ae --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingleton.java @@ -0,0 +1,50 @@ +package top.fjy8018.designpattern.pattern.creational.singleton; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 基于容器(集合)实现单例 + * 适用于类加载时有多个对象需要实例化场景 + * + * @author F嘉阳 + * @date 2018-09-24 22:31 + */ +@Slf4j +public class ContainerSingleton { + private static Map instancesMap = new HashMap<>(); + + private ContainerSingleton() { + } + + public static void putInstance(String key, Object instance) { + if (StringUtils.isNotBlank(key) && instance != null) { + if (!instancesMap.containsKey(key)) { + instancesMap.put(key, instance); + } + } + } + + public static Object getInstance(String key) { + return instancesMap.get(key); + } + + /** + * 线程安全测试 + * + * @param key + * @param instance + */ + public static void putInstance2(String key, Object instance) throws InterruptedException { + if (StringUtils.isNotBlank(key) && instance != null) { + if (!instancesMap.containsKey(key)) { + Thread.sleep(1000); + log.debug("放入实例:" + instance); + instancesMap.put(key, instance); + } + } + } +} diff --git a/src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonHashtable.java b/src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonHashtable.java new file mode 100644 index 0000000..a338134 --- /dev/null +++ b/src/main/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonHashtable.java @@ -0,0 +1,50 @@ +package top.fjy8018.designpattern.pattern.creational.singleton; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.Hashtable; +import java.util.Map; + +/** + * 基于容器(集合)实现单例(线程不安全) + * {@link Hashtable} 实现(不建议) + * + * @author F嘉阳 + * @date 2018-09-24 22:31 + */ +@Slf4j +public class ContainerSingletonHashtable { + private static Map instancesMap = new Hashtable<>(); + + private ContainerSingletonHashtable() { + } + + public static void putInstance(String key, Object instance) { + if (StringUtils.isNotBlank(key) && instance != null) { + if (!instancesMap.containsKey(key)) { + instancesMap.put(key, instance); + } + } + } + + public static Object getInstance(String key) { + return instancesMap.get(key); + } + + /** + * 线程安全测试 + * + * @param key + * @param instance + */ + public static void putInstance2(String key, Object instance) throws InterruptedException { + if (StringUtils.isNotBlank(key) && instance != null) { + if (!instancesMap.containsKey(key)) { + Thread.sleep(1000); + log.debug("放入实例:" + instance); + instancesMap.put(key, instance); + } + } + } +} diff --git a/src/test/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonTest.java b/src/test/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonTest.java new file mode 100644 index 0000000..10de4f1 --- /dev/null +++ b/src/test/java/top/fjy8018/designpattern/pattern/creational/singleton/ContainerSingletonTest.java @@ -0,0 +1,79 @@ +package top.fjy8018.designpattern.pattern.creational.singleton; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +@Slf4j +class ContainerSingletonTest { + + /** + * 直接使用{@link java.util.HashMap} 只会放入一个值,但后面放的值会覆盖首次放入的值 + * + * @throws InterruptedException + */ + @Test + void getInstanceHashMapUnsafe() throws InterruptedException { + Thread thread1 = new Thread(new MyHashMapRunnable()); + Thread thread2 = new Thread(new MyHashMapRunnable()); + + thread1.start(); + thread2.start(); + + Thread.sleep(2000); + log.debug("finish"); + } + + /** + * 使用{@link java.util.Hashtable} {@link java.util.concurrent.ConcurrentHashMap}可以控制并发,只会放入一个值,但后面放的值会覆盖首次放入的值,效果实际同{@link java.util.HashMap} + * 对于Hashtable,在一定程度保证线程安全,但影响了性能 + * 对于ConcurrentHashMap,由于使用了静态的ConcurrentHashMap,并直接操作了map,也不是绝对线程安全 + * + * @throws InterruptedException + */ + @Test + void getInstanceHashtableUnsafe() throws InterruptedException { + Thread thread1 = new Thread(new MyHashtableRunnable()); + Thread thread2 = new Thread(new MyHashtableRunnable()); + + thread1.start(); + thread2.start(); + + Thread.sleep(2000); + log.debug("finish"); + } + + @Test + void putInstance2() { + } + + private class MyHashMapRunnable implements Runnable { + @Override + public void run() { + try { + ContainerSingleton.putInstance2("object", new Object()); + // 等待其他线程放入对象后取值 + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Object singleton = ContainerSingleton.getInstance("object"); + log.info(Thread.currentThread().getName() + " " + singleton); + } + } + + private class MyHashtableRunnable implements Runnable { + @Override + public void run() { + try { + ContainerSingletonHashtable.putInstance2("object", new Object()); + // 等待其他线程放入对象后取值 + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + Object singleton = ContainerSingletonHashtable.getInstance("object"); + log.info(Thread.currentThread().getName() + " " + singleton); + } + } +} \ No newline at end of file