保证整个系统中一个类只有一个对象的实例,实现这种功能的方式就叫单例模式。 单例模式实现格式一般为:
构造方法私有化定义一个该类的静态变量对外提供一个public返回实例的静态方法在初始化类的时候,不创建唯一的实例,而是等到真正需要用到的时候才创建。可以理解为一个懒人,饿的时候才想起要创建一个(吃饭)对象。 注意必须加上同步,否则有可能依然创建多个实例。
代码如下:
//多线程下的单例模式 懒汉模式 public class A1 { //定义一个该类的静态变量 public static A1 a; //构造方法私有化 private A1(){ } //对外提供一个public返回实例的静态方法 public synchronized static A1 getInstance(){ if (a==null){ //如果该变量为null,生成该对象 a = new A1(); return a; }else { //如果不为不null,直接返回该对象 return a; } } } //测试类 public class TestA1 extends Thread{ @Override public void run() { //调用A1的getInstance()方法的hashCode值,即对象的哈希值,来判断是否为单例 System.out.println(Thread.currentThread().getName()+"--->"+A1.getInstance().hashCode()); } public static void main(String[] args) { TestA1 threadA1 = new TestA1(); threadA1.setName("苹果"); threadA1.start(); TestA1 threadA2 = new TestA1(); threadA2.setName("香蕉"); threadA2.start(); TestA1 threadA3 = new TestA1(); threadA3.setName("橘子"); threadA3.start(); } }运行结果如下,通过哈希值可以判断是一个单例对象。
在初始化的时候,就创建了唯一的实例,不管是否需要用到。就像一个饿了好久的人,一上来就先创建一个(吃饭)对象。不需要自己加同步,一定产生唯一的实例。
代码如下:
//单例模式之饿汉模式 public class E { //定义一个该类的静态变量 private static E e = new E(); //构造方法私有化 private E(){ } //对外提供一个public返回实例的静态方法 public static E getInstance(){ return e; } } //测试类 public class TestE extends Thread{ @Override public void run() { //调用E的getInstance()方法的hashCode值,即对象的哈希值,来判断是否为单例 System.out.println(Thread.currentThread().getName()+"--->"+E.getInstance().hashCode()); } public static void main(String[] args) { TestE testE1 = new TestE(); testE1.setName("苹果"); testE1.start(); TestE testE2 = new TestE(); testE2.setName("香蕉"); testE2.start(); TestE testE3 = new TestE(); testE3.setName("橘子"); testE3.start(); } }运行结果如下,通过哈希值可以判断是一个单例对象。
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的。
从实现方式来讲他们最大的区别就是懒汉式是延时加载,懒汉式是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,饿汉式无需关注多线程问题,写法简单明了,能用则用。但是它是加载类时创建实例。所以如果是一个工厂模式,缓存了很多实例,那么就得考虑效率问题,因为这个类一加载则把所有实例不管用不用一块创建。
两者建立单例对象的时间不同。“懒汉式”是在你真正用到的时候才去建这个单例对象,“饿汉式”是在不管用不用得上,一开始就建立这个单例对象。