单例模式是指,某个类只能被实例化一次,在JVM中,只能有一个相应的对象存在。
第一种实现方式:饿汉式
package hungry;
public class HungryMode {
private HungryMode(){
//构造方法私有,以防外部通过new来实例化
}
private static HungryMode instance = new HungryMode(); //准备一个该类的实例化对象,因为在类中定义,所以只有一个该对象。
public static HungryMode getInstance(){
return instance; //让调用者通过静态方法即可调用定义好的instance
}
}
package hungry;
public class Test {
public static void main(String[] args){
HungryMode hm1 = HungryMode.getInstance();
HungryMode hm2 = HungryMode.getInstance();
HungryMode hm3 = HungryMode.getInstance();
System.out.println(hm1==hm2);
System.out.println(hm2==hm3);
System.out.println(hm3==hm1);
}
}
第二种实现方式:懒汉式
懒汉式写法只适用于单线程模式。如果执行到类方法中的if(instance == null),很有可能其他线程也进行到这里并同时实例化出新的FullMode类对象。这不符合单例模式要求,故只能只用于单线程。
也可通过加synchronized关键字解决,但降低了效率。
package full;
public class FullMode {
private FullMode(){
}
private static FullMode instance;
public static FullMode getInstance(){
if(instance == null){
instance = new FullMode();
}//只有当外部其他类调用本类的static方法时,才实例化出一个对象。之后再调用,都返回这唯一一个对象。
return instance;
}
}
package full;
public class Test {
public static void main(String[] args){
FullMode fm1 = FullMode.getInstance();
FullMode fm2 = FullMode.getInstance();
FullMode fm3 = FullMode.getInstance();
System.out.println(fm1 == fm2);
System.out.println(fm2 == fm3);
System.out.println(fm3 == fm1);
}
}
第三种实现方式:双检查
第一次进行判空,使得同一时刻只能有一个线程进入synchronized区域。第二次判空,如果instance是null,则线程就实例化一个类对象instance。如果不为null,则直接返回已经实例化的instance。适合多线程情况。
package full;
import java.io.File;
public class Test2 {
public static void main(String[] args){
Th1 t1 = new Th1();
t1.start();
Th2 t2 = new Th2();
t2.start();
Th3 t3 = new Th3();
t3.start();
System.out.println(t1.fm21);
System.out.println(t2.fm22);
System.out.println(t3.fm23);
}
}
package full;
public class Th1 extends Thread{
static FullMode2 fm21;
public void run(){
fm21 = FullMode2.getInstance();
}
}
package full;
public class Th2 extends Thread{
static FullMode2 fm22;
public void run(){
fm22 = FullMode2.getInstance();
}
}
package full;
public class Th3 extends Thread{
static FullMode2 fm23;
public void run(){
fm23 = FullMode2.getInstance();
}
}
package full;
public class FullMode2 {
private static volatile FullMode2 instance;
private FullMode2(){
}
public static FullMode2 getInstance(){
if(instance == null){
synchronized(FullMode2.class){
if(instance == null){
instance = new FullMode2();
}
}
}
return instance;
}
}
第四种实现方式:静态内部类
类的静态属性只会在第一次加载类的时候被初始化。这里的线程安全由JVM来保障。在类进行初始化时,其他线程无法进入。
package StaticInnerClass;
public class staticInnerMode {
private staticInnerMode(){
}
private static class SingletonInstance{
private static final staticInnerMode instance = new staticInnerMode();
}
public static staticInnerMode getInstance(){
return SingletonInstance.instance;
}
}
package StaticInnerClass;
public class Test {
public static void main(String[] args){
staticInnerMode s1 = staticInnerMode.getInstance();
staticInnerMode s2 = staticInnerMode.getInstance();
staticInnerMode s3 = staticInnerMode.getInstance();
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
}
第五种实现方式:枚举
package enumMode;
public enum SingletonEnum {
INSTANCE;
int i = 0;
public void screen(){
System.out.println("第"+(++i)+"次调用单例对象");
}
}
package enumMode;
public class Test {
public static void main(String[] args){
SingletonEnum se1 = SingletonEnum.INSTANCE;
SingletonEnum se2 = SingletonEnum.INSTANCE;
SingletonEnum se3 = SingletonEnum.INSTANCE;
System.out.println(se1);
se1.screen();
System.out.println(se2);
se2.screen();
System.out.println(se3);
se3.screen();
}
}
通过底层保证了单例的实现,且防止了反序列化。。