package com.learn.design.pattern.creational.singleton;
/**
* 是基于ThreadLocal的
* 所以必不可少要使用这个类
*
* 我们看一下这个类
* ThreadLocal会为每一个线程提供一个独立 的线程复本
* 本身ThreadLocal是基于static class ThreadLocalMap这个类来实现的
* 所以我们在调用它的get方法的时候呢
* 默认走的就是这个map
* 不用指定key
* 他维持了线程间的隔离
* 接着回来
* 那ThreadLocal隔离了多个线程
* 对数据的访问冲突
* 那对于多线程资源共享的问题
* 我们想象一下
* 我们使用同步锁
* 那其实是以时间换空间的方式
* 因为要排队
* 那如果要使用ThreadLocal呢
* 就是空间换时间的方式
* 很简单
* 可以创建很多对象
* 至少在一个线程里
* 创建一个
* 但是对于这个线程
* 他获取这个对象
* 是唯一的
* 正如Test这个主函数
* 所执行的结果一样
* main里面拿的都是同一个
* 基于ThreadLocal带引号的单例模式呢
* 为每个线程都提供了一个对象
* 因此在多线程访问的时候
* 相互不会影响
* 那这个就是基于ThreadLocal带引号的单例模式实现方案
*
*
*
* @author Leon.Sun
*
*/
public class ThreadLocalInstance {
/**
* 这个ThreadLocal里面放的泛型
* 肯定就是我们的这个对象
* 那名字也叫这个类名吧
* 然后我们直接重写里面的方法
* 重写初始化方法
* 我们可以认为这个是一个匿名类
*
*
*/
private static final ThreadLocal<ThreadLocalInstance> threadLocalInstanceThreadLocal
= new ThreadLocal<ThreadLocalInstance>(){
@Override
protected ThreadLocalInstance initialValue() {
/**
* 这里return很简单
* 初始化的时候直接new一个这样的对象
* 那这块就声明好了
* 属于这个类比较重要的初始化
*
*
*/
return new ThreadLocalInstance();
}
};
/**
* 把他的私有构造器补上
*
*
*/
private ThreadLocalInstance(){
}
/**
* 然后对外开放一个getInstance的方法
* 返回的肯定是这个对象
*
*
* @return
*/
public static ThreadLocalInstance getInstance(){
/**
* 直接从threadLocalInstanceThreadLocal对象中get
* 那这个单例模式就写完了
* 注意它是带引号的单例
* 那么现在测试一下
* 还是来到Test里面
*
*
*/
return threadLocalInstanceThreadLocal.get();
}
}
package com.learn.design.pattern.creational.singleton;
public class T implements Runnable {
@Override
public void run() {
// LazySingleton lazySingleton = LazySingleton.getInstance();
// System.out.println(Thread.currentThread().getName()+" "+lazySingleton);
// LazyDoubleCheckSingleton instance = LazyDoubleCheckSingleton.getInstance();
// StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();;
// ContainerSingleton.putInstance("object",new Object());
// Object instance = ContainerSingleton.getInstance("object");
ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
System.out.println(Thread.currentThread().getName()+" "+instance);
}
}
package com.learn.design.pattern.creational.singleton;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// LazySingleton lazySingleton = LazySingleton.getInstance();
/**
* 首先主线程拿到的对象是同一个ThreadLocalInstance@7852e922
* 注意这里全部都是ThreadLocalInstance@7852e922
* Thread0拿到的是@4d25007
* Thread1拿到的是@2dec1376
*
*
*/
System.out.println("main thread"+ThreadLocalInstance.getInstance());
System.out.println("main thread"+ThreadLocalInstance.getInstance());
System.out.println("main thread"+ThreadLocalInstance.getInstance());
System.out.println("main thread"+ThreadLocalInstance.getInstance());
System.out.println("main thread"+ThreadLocalInstance.getInstance());
System.out.println("main thread"+ThreadLocalInstance.getInstance());
/**
* 因为ThreadLocal是基于线程的
* 所以我们把T里面的代码改一下
* 这两个线程拿到的对象 并不是同一个
* 那我们想象一下
* 现在Main本身是一个线程
* 这里面又开了两个线程
* 那如果在main里面拿呢
*
*
*/
Thread t1 = new Thread(new T());
Thread t2 = new Thread(new T());
t1.start();
t2.start();
System.out.println("program end");
// HungrySingleton instance = HungrySingleton.getInstance();
// EnumInstance instance = EnumInstance.getInstance();
// instance.setData(new Object());
// ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
// oos.writeObject(instance);
// File file = new File("singleton_file");
// ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
// HungrySingleton newInstance = (HungrySingleton) ois.readObject();
// EnumInstance newInstance = (EnumInstance) ois.readObject();
// System.out.println(instance.getData());
// System.out.println(newInstance.getData());
// System.out.println(instance.getData() == newInstance.getData());
// Class objectClass = HungrySingleton.class;
// Class objectClass = StaticInnerClassSingleton.class;
// Class objectClass = LazySingleton.class;
// Class objectClass = EnumInstance.class;
// Constructor constructor = objectClass.getDeclaredConstructor();
// Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
//
// constructor.setAccessible(true);
// EnumInstance instance = (EnumInstance) constructor.newInstance();
// EnumInstance instance = (EnumInstance) constructor.newInstance("Geely",666);
//
// LazySingleton newInstance = (LazySingleton) constructor.newInstance();
// LazySingleton instance = LazySingleton.getInstance();
// StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
// StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance();
// HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
// HungrySingleton instance = HungrySingleton.getInstance();
// System.out.println(instance);
// System.out.println(newInstance);
// System.out.println(instance == newInstance);
// EnumInstance instance = EnumInstance.getInstance();
// instance.printTest();
}
}
基于ThreadLocal的这种单例写法,那这个单例可能就要画一个引号了,因为他不能保证整个应用全局唯一,但是他可以
保证线程唯一,那怎么理解呢,我们通过coding吧,首先我们创建一个类,ThreadLocalInstance