单例模式:
单例模式就是采用了一定的方法,保证了再整个系统当中,对某个类的实例对象都只存在唯一的一个。
单例模式的饿汉式和懒汉式写法
饿汉式写法:饿汉式,顾名思义就是很饥饿的意思一上来就创建对象
public class SingletonTest1 {
public static void main(String[] args)
{
SingletonDome1 singletonDome1 = SingletonDome1.singletonDome1;
SingletonDome1 singletonDome2 = SingletonDome1.singletonDome1;
System.out.println(singletonDome1==singletonDome2);
}
}
// 饿汉式,一调用就拿到改对象
class SingletonDome1{
// 1. 私有化构造器 目的外部无法创建实例
private SingletonDome1(){}
// 2.声明当前类的对象为static保证调用的是用一个实例,并初始化对象
public final static SingletonDome1 singletonDome1=new SingletonDome1();
}
懒汉式写法:懒汉式,证明就是比较懒,需要在使用的时候在创建
public class SingletonTest2 {
public static void main(String[] args)
{
SingletonDome2 singletonDome3 = SingletonDome2.getSingletonDome2();
SingletonDome2 singletonDome4 = SingletonDome2.getSingletonDome2();
System.out.println(singletonDome3==singletonDome4);
}
}
// 懒汉式,需要使用的时候在拿到改对象
class SingletonDome2{
// 1. 私有化构造器 目的外部无法创建实例
private SingletonDome2(){}
// 2.声明当前类的对象为static,不立即创建对象
private static SingletonDome2 singletonDome2=null;
// 3.提供外部能获取到私有对象的方法,并且需要使用static来修饰,证明是共享的
public static SingletonDome2 getSingletonDome2(){
// 判断是否没有该对象的实例,如果没有就创建,如果有就使用原来的
if(singletonDome2==null){
singletonDome2= new SingletonDome2();
}
return singletonDome2;
}
}
饿汉式和懒汉式的区别:
1.饿汉式的坏处:因为是一调用该方法就创建对象,所以导致了对象创建的时间过长。
2.饿汉式的好处:线程安全
3.懒汉式的好处:延迟创建对象
4.懒汉式的坏处:线程不安全
既然说到懒汉式线程不安全那怎么证明,证明之后怎么样来保证在多线程的情况下保证他线程安全呢?
证明其懒汉式线程不安全
public class SingletonTest2 {
public static void main(String[] args)
{
// 创建二个线程
Thread thread1=new Thread(){
@Override
public void run()
{
SingletonDome2 singletonDome3 = SingletonDome2.getSingletonDome2();
System.out.println("singletonDome3的地址值"+singletonDome3);
}
};
Thread thread2=new Thread(){
@Override
public void run()
{
SingletonDome2 singletonDome4 = SingletonDome2.getSingletonDome2();
System.out.println("singletonDome4的地址值"+singletonDome4);
}
};
thread1.start();
thread2.start();
}
}
// 懒汉式,需要使用的时候在拿到改对象
class SingletonDome2{
// 1. 私有化构造器 目的外部无法创建实例
private SingletonDome2(){}
// 2.声明当前类的对象为static,不立即创建对象
private static SingletonDome2 singletonDome2=null;
// 3.提供外部能获取到私有对象的方法,并且需要使用static来修饰,证明是共享的
public static SingletonDome2 getSingletonDome2(){
// 判断是否没有该对象的实例,如果没有就创建,如果有就使用原来的
if(singletonDome2==null){
try
{
// 让线程休眠 更好看到结果
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
singletonDome2= new SingletonDome2();
}
return singletonDome2;
}
}
以上测试代码的运行结果:二个地址值不一致,证明拿到的对象不一致
懒汉式安全的写法:添加synchronized锁
public class SingletonTest2 {
public static void main(String[] args)
{
// 创建二个线程
Thread thread1=new Thread(){
@Override
public void run()
{
SingletonDome2 singletonDome3 = SingletonDome2.getSingletonDome2();
System.out.println("singletonDome3的地址值"+singletonDome3);
}
};
Thread thread2=new Thread(){
@Override
public void run()
{
SingletonDome2 singletonDome4 = SingletonDome2.getSingletonDome2();
System.out.println("singletonDome4的地址值"+singletonDome4);
}
};
thread1.start();
thread2.start();
}
}
// 懒汉式,需要使用的时候在拿到改对象
class SingletonDome2{
// 1. 私有化构造器 目的外部无法创建实例
private SingletonDome2(){}
// 2.声明当前类的对象为static,不立即创建对象
private static SingletonDome2 singletonDome2=null;
// 3.提供外部能获取到私有对象的方法,并且需要使用static来修饰,证明是共享的
public static SingletonDome2 getSingletonDome2(){
// 添加Java自带的锁,锁住该类
synchronized (SingletonDome2.class)
{
// 判断是否没有该对象的实例,如果没有就创建,如果有就使用原来的
if (singletonDome2 == null)
{
try
{
// 休眠时间变长,检查是否线程安全
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
singletonDome2 = new SingletonDome2();
}
};
return singletonDome2;
}
}
运行结果:多次运行之后得到的结果还是一致的状态,证明拿到的对象是同一个对象