容器(集合)实现单例,测试线程安全性
This commit is contained in:
7
pom.xml
7
pom.xml
@@ -46,6 +46,13 @@
|
|||||||
<version>2.11.0</version>
|
<version>2.11.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user