java设计模式1:单例模式懒汉和饿汉线程安全(synchronized+volatile)

懒汉模式

懒汉模式没啥好讲,直接代码


public class test{
	
    public static void main(String args[]){
        Student student1 = Student.getInstance();
        Student student2 = Student.getInstance();
		System.out.println(student1 == student2);
    }
}

/**
懒汉模式
1、构造方法私有化
2、私有静态对象,创建
3、public的静态方法获取对象
*/
class Student{
	// 私有静态变量
	private static Student student = new Student();
	
	// 构造方法私有化
	private Student(){
		super();
	}
	
	// public的静态方法获取对象
	public static Student getInstance(){
		return student;
	}
}


饿汉模式

1.饿汉模式注意线程安全问题,new对象前,需要加锁,并在此判断对象是否为空
2.使用volatile修饰对象的原因

下文Instance类变量如果没有用volatile关键字修饰的,会导致这样一个问题:
线程1正在new Instance(),且instance引用的对象有可能还没有完成初始化。(执行了下面说明中1、2步骤,没执行3步骤)
此时线程2执行到1号位置,代码读取到instance,此时已经有内存了,但是还没完成初始化,会不为null。
此时需要使用volatile,
volatile主要的原因是重排序。重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。(禁止重排序,顺序为1、2、3)

说明:
new Student();创建了一个对象,这一行代码可以分解成3个操作:
memory = allocate();  // 1:分配对象的内存空间
ctorInstance(memory); // 2:初始化对象
instance = memory;  // 3:设置instance指向刚分配的内存地址
根源在于代码中的2和3之间,可能会被重排序。例如:
memory = allocate();  // 1:分配对象的内存空间
instance = memory;  // 3:设置instance指向刚分配的内存地址
// 注意,此时对象还没有被初始化!
ctorInstance(memory); // 2:初始化对象
因为被volatile关键字修饰的变量是被禁止重排序的。
所以只需要做一点小的修改(把instance声明为volatile型),就可以实现线程安全的延迟初始化

代码
public class test{
	
    public static void main(String args[]){
        Student student1 = Student.getInstance();
        Student student2 = Student.getInstance();
		System.out.println(student1 == student2);
    }
}

/**
饿汉模式
1、构造方法私有化
2、私有静态对象(volatile修饰)
3、public的静态方法获取对象
	1.判断对象是否存在
	2.加锁,保证线程安全。再次判断,创建对象。
注解:
为什么使用volatile修饰
*/
class Student{
	// 私有静态变量
	private static volatile Student instance;
	
	// 构造方法私有化
	private Student(){
		super();
	}
	
	// public的静态方法获取对象
	public static Student getInstance(){
		// 判断对象是否存在
		if(instance == null){//*1号位置**//
			// 加锁,保证线程安全
			synchronized(Student.class){
				// 再次判断(第一次获取对象时才是空。对象有了之后,这边不会走)
				if(instance == null){
					// 创建对象
					instance  = new Student();
				}
			}
		}
		return instance;
	}
}

你可能感兴趣的:(设计模式)