单例模式
饿汉式单例模式
饿汉式即类被加载的时候就会生成单例实例。
//饿汉式
public class Singleton1 {
private static final Singleton1 instance = new Singleton1();
private Singleton1() {
System.out.println("创建饿汉式单例成功");
}
public static Singleton1 getInstance(){
return instance;
}
public static void otherMethod(){
System.out.println("执行其他方法");
}
}
破坏
反射破坏
public static Object reflect(Class className) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Constructor con = className.getDeclaredConstructor();
con.setAccessible(true);
return con.newInstance();
}
预防反射破坏单例;
private Singleton1() {
if(instance!=null){
throw new RuntimeException("单例对象不能重复创建");
}
System.out.println("创建饿汉式单例成功");
}
序列化破坏
要求serializable
,新对象不走构造方法。
public static void serialAble(Object instance) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(instance);
ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
System.out.println(ois.readObject());
}
预防序列化破坏:
public Object readResolve(){
return instance;
}
unsafe破坏
public static void unsafe(Class<?> clazz){
Object o=UnsafeUtils.getUnsafe().allocateInstance(clazz);
System.out.println("创建实例成功");
}
不好避免
枚举类单例模式
public enum Singleton2 {
MALE,FEMALE
}
public enum Singleton2 {
instance;
private Singleton2(){
System.out.println("枚举饿汉式创建成功");
}
public static Singleton2 getInstance(){
return instance;
}
public static void otherMethod(){
System.out.println("执行其他方法");
}
@Override
public String toString() {
return getClass().getName()+"@"+Integer.toHexString(hashCode());
}
public static void main(String[] args) {
Singleton2.otherMethod();
Singleton2 instance1 = Singleton2.getInstance();
Singleton2 instance2 = Singleton2.getInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
不好破坏,反射也不行。
懒汉式单例模式
在第一次使用的时候才会创建实例
package Singleton;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
public class Singleton3 {
private static Singleton3 instance = null ;
private Singleton3() {
if(instance!=null){
throw new RuntimeException("单例对象不能重复创建");
}
System.out.println("创建饿汉式单例成功");
}
public static Singleton3 getInstance(){
if(instance==null){
instance=new Singleton3();
}
return instance;
}
public static void otherMethod(){
System.out.println("执行其他方法");
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
//1 测试
Singleton3.otherMethod();
Singleton3 instance1 = Singleton3.getInstance();
Singleton3 instance2=Singleton3.getInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
在多线程情况下会出现线程安全问题。应用DCL懒汉式单例模式解决
DCL懒汉式单例模式
又称双检锁单例模式
public class Singleton4 {
private Singleton4() {
System.out.println("创建饿汉式单例成功");
}
//添加voilate关键字
private voilate static Singleton4 instance = null ;
public static Singleton4 getInstance(){
//双重检查锁
if(instance==null){
synchronized (Singleton4.class){
if(instance==null){
instance=new Singleton4();
}
}
}
return instance;
}
public static void otherMethod(){
System.out.println("执行其他方法");
}
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
//1 测试
Singleton4.otherMethod();
Singleton4 instance1 = Singleton4.getInstance();
Singleton4 instance2=Singleton4.getInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
内部类饿汉式
内部类在使用时初始化,是线程安全的。
public class Singleton5 {
private Singleton5(){
System.out.println("内部类饿汉式初始化");
}
public static class Holder{
static Singleton5 instance =new Singleton5();
}
public static Singleton5 getInstance(){
return Holder.instance;
}
public static void otherMethod(){
System.out.println("执行其他方法");
}
}
在jdk中的体现
饿汉式
Runtime 饿汉式单例模式
private static Runtime currentRuntime = new Runtime();
懒汉式
System.console()
public static Console console() {
if (cons == null) {
synchronized (System.class) {
cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
}
}
return cons;
}