/**
* 饿汉式单例(提前把对象创建)
* 可能会浪费空间,提前把对象创建好了,但是不一定会用。
*/
public class Hungry {
private Hungry(){
}
private final static Hungry HUNGRY=new Hungry();
public static Hungry getInstance(){
return HUNGRY;
}
}
单线程下可用,多线程下不可用,存在多线程并发问题。
/**
* 懒汉式单例(当使用时再创建对象)
* 单线程下可用
*/
public class LazyMan {
private LazyMan(){
}
private static LazyMan lazyMan;
public LazyMan getInstnce(){
if(lazyMan==null){
lazyMan=new LazyMan();
}
return lazyMan;
}
}
用多线程并发测试:
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private static LazyMan lazyMan;
public static LazyMan getInstance(){
if(lazyMan==null){
lazyMan=new LazyMan();
}
return lazyMan;
}
//多线程并发测试
public static void main(String[] args){
for(int i=0;i<10;i++){
new Thread(()->{
lazyMan.getInstance();
}).start();
}
}
}
于是进阶为(加锁)DCL懒汉式(成为双重检测锁模式):
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private static LazyMan lazyMan;
//双重检测锁模式的懒汉式单例,DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized (LazyMan.class){
if(lazyMan==null){
lazyMan=new LazyMan();
}
}
}
return lazyMan;
}
//多线程并发测试
public static void main(String[] args){
for(int i=0;i<10;i++){
new Thread(()->lazyMan.getInstance()
).start();
}
}
}
每一个线程开启,都只有一个单例对象。
DCL懒汉式单例再改进(添加volatle消除指令重排):
public class LazyMan {
private LazyMan(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private volatile static LazyMan lazyMan;
//双重检测锁模式的懒汉式单例,DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized (LazyMan.class){
if(lazyMan==null){
lazyMan=new LazyMan();//不是原子性操作
/**不是原子性操作会发生以下三操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象指向这个空间
*
*
* 会导致123或132顺序执行
* 若A线程顺序是132,又来了一个B线程,
* 则此时lazyMan没有完成构造,则会发生问题。(指令重排)
*/
}
}
}
return lazyMan;
}
//多线程并发测试
public static void main(String[] args){
for(int i=0;i<10;i++){
new Thread(()->lazyMan.getInstance()
).start();
}
}
}
/**
* 静态内部类
*/
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
public static class InnerClass{
private static final Holder HOLDER=new Holder();
}
}
以上单例方法都有问题,因为存在反射技术!!!
演示反射破解(两重检测锁模式)DCL进阶版懒汉式:
//反射
public static void main(String[] args) throws Exception {
LazyMan instance1 = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
进阶:在无参构造器中进行判断(成为三层检测锁模式),再执行:
public class LazyMan {
private LazyMan(){
synchronized (LazyMan.class){
if(lazyMan!=null){
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
}
private volatile static LazyMan lazyMan;
//双重检测锁模式的懒汉式单例,DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized (LazyMan.class){
if(lazyMan==null){
lazyMan=new LazyMan();//不是原子性操作
/**不是原子性操作会发生以下三操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象指向这个空间
*
*
* 会导致123或132顺序执行
* 若A线程顺序是132,又来了一个B线程,
* 则此时lazyMan没有完成构造,则会发生问题。
*/
}
}
}
return lazyMan;
}
//反射
public static void main(String[] args) throws Exception {
LazyMan instance1 = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
使用反射再次破解时,把两个对象都用反射的方法newInstance() 创建出来:
//反射
public static void main(String[] args) throws Exception {
// LazyMan instance1 = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance1 = declaredConstructor.newInstance();
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
public class LazyMan {
private static boolean muzi=false;
private LazyMan(){
synchronized (LazyMan.class){
if(muzi==false){
muzi=true;
} else{
throw new RuntimeException("不要试图使用反射破坏异常");
}
}
}
private volatile static LazyMan lazyMan;
//双重检测锁模式的懒汉式单例,DCL懒汉式
public static LazyMan getInstance(){
if(lazyMan==null){
synchronized (LazyMan.class){
if(lazyMan==null){
lazyMan=new LazyMan();//不是原子性操作
/**不是原子性操作会发生以下三操作
* 1.分配内存空间
* 2.执行构造方法,初始化对象
* 3.把这个对象指向这个空间
*
*
* 会导致123或132顺序执行
* 若A线程顺序是132,又来了一个B线程,
* 则此时lazyMan没有完成构造,则会发生问题。
*/
}
}
}
return lazyMan;
}
//反射
public static void main(String[] args) throws Exception {
// LazyMan instance1 = LazyMan.getInstance();
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance1 = declaredConstructor.newInstance();
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
}
反射破解(通过反射获取muzi属性,并修改):
//反射
public static void main(String[] args) throws Exception {
// LazyMan instance1 = LazyMan.getInstance();
Field muzi = LazyMan.class.getDeclaredField("muzi");
muzi.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);
LazyMan instance1 = declaredConstructor.newInstance();
muzi.set(instance1,false);
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
/**
* 枚举
*/
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}