饿汉式
特点
a)私有构造器
b)持有该类属性
c)对外提供获取实例的静态方法
使用对象才去加载
优点:在类加载时就创建对象,无延迟,线程是安全的
缺点:浪费内存,在反射和反序列化时是不安全的(反射会存在两个对象)
package single;
import java.io.Serializable;
public class Singleton1 implements Serializable {
private static Singleton1 singleton1 = new Singleton1 ();
private Singleton1 () { }
public static Singleton1 getSingleton1 () {
return singleton1;
}
//解决序列化不安全的方法
private Object readResolve(){
return singleton1;
}
}
package single;
import java.io.*;
public class SerializeUtil {
public static void serialize (Object object) {
ObjectOutputStream oos = null;
File file = new File ("obj");
try {
oos = new ObjectOutputStream (new FileOutputStream (file));
oos.writeObject (object);
oos.flush ();
} catch (IOException e) {
e.printStackTrace ();
} finally {
try {
oos.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
}
public static Object unserialize () {
ObjectInputStream ois = null;
try {
File file = new File ("obj");
ois = new ObjectInputStream (new FileInputStream (file));
Object object = ois.readObject ();
return object;
} catch (IOException e) {
e.printStackTrace ();
} catch (ClassNotFoundException e) {
e.printStackTrace ();
} finally {
try {
ois.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
return ois;
}
}
package single;
import org.junit.Test;
import java.io.Serializable;
import java.lang.reflect.Constructor;
public class Single1Test {
@Test
public void test1(){
Singleton1 s1 = Singleton1.getSingleton1 ();
Singleton1 s2 = Singleton1.getSingleton1 ();
System.out.println (s1 == s2);
}
@Test
public void test2(){
for (int i = 0;i < 20;i++){
new Thread (new Runnable () {
@Override
public void run () {
System.out.println (Singleton1.getSingleton1 ());
}
}).start ();
}
}
@Test
public void test3() throws Exception{
Class clazz = Singleton1.class;
Constructor constructor = clazz.getDeclaredConstructor ();
constructor.setAccessible (true);
Singleton1 s1 = Singleton1.getSingleton1 ();
Singleton1 s2 = (Singleton1) constructor.newInstance ();
System.out.println (s1 == s2);
System.out.println (s1);
System.out.println (s2);
}
@Test
public void test4(){
//Singleton1 s1 = Singleton1.getSingleton1 ();
//SerializeUtil.serialize (s1);
Singleton1 s1 = (Singleton1) SerializeUtil.unserialize ();
Singleton1 s2 = (Singleton1) SerializeUtil.unserialize ();
System.out.println (s1 == s2);
}
}
登记式
特点
不直接创建static对象,在调用 getSingleton2();时,进行创建实例
优点:线程安全,防止反射攻击
缺点:反序列化不安全
package single;
public class Singleton2 {
private static class SingletonHolder{
private static Singleton2 singleton2 = new Singleton2 ();
}
private Singleton2 () {
System.out.println ("Singleton2 loader");
if (SingletonHolder.singleton2 != null){
throw new IllegalStateException ();
}
}
public static Singleton2 getSingleton2(){
return SingletonHolder.singleton2;
}
private Object readResolve(){
return SingletonHolder.singleton2;
}
}
枚举式
特点
立即加载创建
优点:线程安全、防止反射攻击、支持序列化、反序列化安全
package single;
public enum Singleton3 {
INSTANCE{
@Override
protected void doSomething () {
System.out.println ("doSomething");
}
};
protected abstract void doSomething();
}
懒汉式
特点
缺点:线程不安全,延迟加载
package single;
public class Singleton4 {
private static Singleton4 singleton4 = null;
public Singleton4 () {
}
public static Singleton4 getSingleton4 () {
if (singleton4 == null){
singleton4 = new Singleton4 ();
}
return singleton4;
}
}
改进:变为线程安全的,加上同步锁 synchronized
package single.lanhanshi;
public class Singleton5 {
//private static Singleton5 singleton5 = null;
private static volatile Singleton5 singleton5 = null;
public Singleton5 () {
}
//public static synchronized Singleton5 getSingleton5 () {
// if (singleton5 == null){
// singleton5 = new Singleton5 ();
// }
// return singleton5;
//}
//public static Singleton5 getSingleton5 () {
// synchronized (Singleton5.class){
// if (singleton5 == null){
// singleton5 = new Singleton5 ();
// }
// }
// return singleton5;
//}
//双检索 线程安全、volatile
public static Singleton5 getSingleton5 () {
if (singleton5 == null){
synchronized (Singleton5.class){
if (singleton5 == null){
singleton5 = new Singleton5 ();
}
}
}
return singleton5;
}
}
singleton5 = new Singleton5 ()会执行如下操作:
(1)分配对象内存空间
(2)初始化对象
(3)singleton5指向(1)中分配的空间
在某些编辑器上,可能会出现指令的重排
(1)分配对象内存空间
(2)singleton5指向(1)中分配的空间(但此时对象没有初始化)
(3)初始化对象
ThreadLocal
特点
不加锁,以空间换时间,为每个线程提供变量的独立副本,可以保证各自线程中是单例的,但是不同线程之间不能保证
package single;
public class Singleton8 {
private static Singleton8 singleton8 = null;
private Singleton8 () {
}
private static final ThreadLocal<Singleton8> threadLocalSingleton = new ThreadLocal<Singleton8> (){ @Override
protected Singleton8 initialValue(){
return new Singleton8 ();
}
};
public static Singleton8 getSingleton8 () {
return threadLocalSingleton.get ();
}
}
CAS(比较交换技术)
特点
无锁乐观策略,线程安全
package single;
import java.util.concurrent.atomic.AtomicReference;
public class Singleton9 {
private static final AtomicReference<Singleton9> singleton9 = new AtomicReference<> ();
private Singleton9 () {
System.out.println ("Singleton9 Loaded");
}
public static final Singleton9 getSingleton9(){
for (;;){
Singleton9 current = singleton9.get ();
if (current != null){
return current;
}
current = new Singleton9 ();
if (singleton9.compareAndSet (null,current));{
return current;
}
}
}
}