容器(集合)实现单例,测试线程安全性

This commit is contained in:
2018-09-25 16:21:24 +08:00
parent 78a266fa86
commit 0e5bad0fc4
4 changed files with 186 additions and 0 deletions

View File

@@ -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<String, Object> 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);
}
}
}
}

View File

@@ -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<String, Object> 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);
}
}
}
}

View File

@@ -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);
}
}
}