单例的代码实现
懒汉模式:
public class LazyInstance implements Serializable{
private static LazyInstance instance;
private LazyInstance(){
}
private static LazyInstance getInstance(){
if(instance==null){
instance=new LazyInstance();
}
return instance;
}
}
弊端,会出现很多问题
1.多线程的问题:
public static void main(String[] args) throws Exception {
//多线程问题
for(int i=0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":"+LazyInstance.getInstance());
}
}).start();
}
}
debugger后选择线程单步走
可以使用锁来解决,但是会出现性能的问题,这个可以加上二次检索来处理下:
private static LazyInstance getInstance(){
if(instance==null){//二次检查
synchronized (LazyInstance.class){
if(instance==null){
instance=new LazyInstance();
}
}
}
return instance;
}
2.反射的问题:
接前面的代码
LazyInstance instance=LazyInstance.getInstance();
Class clazz =LazyInstance.class;
Constructor declaredConstructor = clazz.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object obj = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(obj);
很容易出现反射攻击,可以在构造器中截个判断,存在过就抛出异常
3.序列化和反序列化
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singletonFile"));
out.writeObject(instance);
ObjectInputStream in = new ObjectInputStream(new FileInputStream("singletonFile"));
LazyInstance newSingleton = (LazyInstance) in.readObject();
System.out.println(newSingleton);
结果一样会出现多例的情况,这个其实可以复写readResolve方法来直接放回的,通过看read的源码可以发现,其实是通过反射newInstance了一个新的,后面重写后可以直接返回原来的覆盖,源码如下:
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();
Class<?> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}
Object obj;
try {
obj = desc.isInstantiable() ? desc.newInstance() : null;
} catch (Exception ex) {
throw (IOException) new InvalidClassException(
desc.forClass().getName(),
"unable to create instance").initCause(ex);
}
passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}
handles.finish(passHandle);
if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
// Filter the replacement object
if (rep != null) {
if (rep.getClass().isArray()) {
filterCheck(rep.getClass(), Array.getLength(rep));
} else {
filterCheck(rep.getClass(), -1);
}
}
handles.setObject(passHandle, obj = rep);
}
}
return obj;
}
重写:
饿汉模式:
public class HuangrySingleton implements Serializable {
private static HuangrySingleton instance = new HuangrySingleton();
private HuangrySingleton(){
if(instance !=null){
throw new RuntimeException("禁止通过反射创建");
}
}
public static HuangrySingleton getInstance(){
return instance;
}
public Object readResolve(){
return (Object) instance;
}
}
通过枚举:
public enum EnumSingleton {
INSTANCE;
public static EnumSingleton getInstance(){
return INSTANCE;
}
}
容器:
public class ContainerSingleton {
private static HashMap<String,Object> map = new HashMap<String, Object>();
private ContainerSingleton(){}
public static void putInstace(String key,Object object){
if(!StringUtils.isEmpty(key) && object !=null){
map.put(key,object);
}
}
public static Object getInstance(String key){
return map.get(key);
}
}
内部类:
public class StaticInnerClassSingleton {
private static class InnerClass{
static {
System.out.println("innerclass");
}
private static StaticInnerClassSingleton
instance = new StaticInnerClassSingleton();
}
private StaticInnerClassSingleton(){
}
public static StaticInnerClassSingleton getInstance(){
System.out.println("getInstance");
return InnerClass.instance;
}
public static void main(String[] args) {
StaticInnerClassSingleton.getInstance();
}
}
线程:
public class ThreadLocalSingleton {
private static ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal(){
@Override
protected Object initialValue() {
return new ThreadLocalSingleton();
}
};
private ThreadLocalSingleton(){}
public static ThreadLocalSingleton getInstance(){
return threadLocal.get();
}
public static void main(String[] args) {
System.out.println(ThreadLocalSingleton.getInstance());
for(int i=0;i<5;i++){
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+": "
+ThreadLocalSingleton.getInstance());
}
}).start();
}
}
}
等多种方式来生成,用的时候要注意多线程,序列化,和反射的问题!