单例模式
Posted 千彧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单例模式相关的知识,希望对你有一定的参考价值。
用于确保一个类只有一个实例,并且这个实例易于被访问。
让类自身负责保存他的唯一实例。这个类可以保证没有其他实例创建,并且他可以提供一个访问实例的方法,来实现单例模式。
(1)把构造方法声明为 private ,确保只能由自己创建,避免外部创建实例或被子类继承从而创建额外实例。
(2)定义一个私有静态的该类的实例作为该类的数据域,确保一个类只有一个实例。
(3)定义一个静态工厂方法,外部类不能实例化一个该类的对象,所有只能用static的方法,提供给其它类调用返回此单例类的唯一实例。
回收站单例类:
1 import java.security.KeyStore.PrivateKeyEntry; 2 3 public class RecycleBin { 4 private static RecycleBin recycleBin = null; 5 /* 6 * 7 *private 构造方法 保证其他类不能通过 new 创建实例 8 */ 9 private RecycleBin() { 10 System.out.println("回收站被创建!"); 11 } 12 13 public static RecycleBin getrecyclebin() { 14 15 if (recycleBin==null) { 16 recycleBin = new RecycleBin(); 17 }else { 18 System.out.println("系统只能有一个回收站,不能重复!"); 19 } 20 21 return recycleBin; 22 } 23 24 void clearbin(){ 25 System.out.println("回收站被清空!"); 26 } 27 28 }
客户测试类:
1 public class SingletonPattern { 2 3 public static void main(String[] args) { 4 RecycleBin x = RecycleBin.getrecyclebin(); 5 x.clearbin(); 6 RecycleBin y = RecycleBin.getrecyclebin(); 7 x.clearbin(); 8 if(x==y){ 9 System.out.println("x和y是相同的实例"); 10 }else { 11 System.out.println("x和y不是相同的实例"); 12 } 13 } 14 15 }
但是涉及到多线程仍然无法保证单例。
线程类:
1 public class Mythread extends Thread { 2 @Override 3 public void run() { 4 RecycleBin x = null; 5 x=RecycleBin.getrecyclebin(); 6 System.out.println(x+":"+x.hashCode()); 7 8 } 9 }
客户测试类:
public class SingletonPattern { public static void main(String[] args) { for(int i = 0;i<10;i++){ Mythread mythread = new Mythread(); mythread.start(); } } }
测试结果:
[email protected]:1013222045 [email protected]:273890709 [email protected]:1000139925 [email protected]:42617544 [email protected]:79380705 [email protected]:1675705343 [email protected]:1374329314 [email protected]:230677907
解决方法 1:使用synchronized关键字
synchronized 的英文意思是“被同步,已同步了”,该该关键字的作用就是为并发线程提供一种同步机制,用于保证在同一时刻最多只有一个线程来执行某段事先定义好要求同步访问的代码。因此,我们可以将一个方法标记为synchronized,迫使线程在执行这个方法前,要等待其他线程离开这个方法,这样就不会有两个线程同时操作该方法了。
于是修改单例类,在getrecyclebin()方法之前加上synchronized关键字,其它代码不变。
加上synchronized关键字之后,线程得到的是一个实例,但是这里又引出一个问题·:效率。每次调用getrecyclebin()的时候都要进行同步,会造成负担。
解决方法 2:双重检查加锁(不适用于1.4及以前版本的java)
利用双重检查加锁,首先检查是否已实现了实例 ,如果还没创建才进行同步,这样只会有第一次同步,效率自然会提高。
单例类:
1 import java.security.KeyStore.PrivateKeyEntry; 2 3 public class RecycleBin { 4 private static RecycleBin recycleBin = null; 5 /* 6 * 7 *private 构造方法 保证其他类不能通过 new 创建实例 8 */ 9 private RecycleBin() { 10 System.out.println("回收站被创建!"); 11 } 12 13 public static RecycleBin getrecyclebin() { 14 15 synchronized (RecycleBin.class) { 16 if (recycleBin==null) { 17 recycleBin = new RecycleBin(); 18 }else { 19 System.out.println("系统只能有一个回收站,不能重复!"); 20 } 21 22 return recycleBin; 23 } 24 25 } 26 27 void clearbin(){ 28 System.out.println("回收站被清空!"); 29 } 30 31 }
synchronized只加在能判断或函数外,如果加在 recycleBin = new RecycleBin(); 上无法起到作用。
因为在第一次访问时,线程的 recycleBin 都为空。必须保证后续线程无法进入判断,否则后续线程仍会创建。
解决方法 3:饿汉式单例
懒汉式:
懒汉式单例指的是当程序第一次访问单例模式实例时才进行创建。
体现对象延迟加载的思想,效率高。尽可能的节约资源,但设计不当会造成线程不安全,代码相对于饿汉式复杂。第一次加载类对象时反应不快。必须处理好多个线程同时访问的问题,需通过双重锁等机制进行控制,可能会导致系统性能受影响。
饿汉式:
饿汉式单例是当程序启动时或单例被加载时,单例类实例就已经创建,所有一开始就new了实例。
对象预先加载,线程是安全的,反应速度快。但是资源利用不高,系统加载时间可能会比较长。
以上是关于单例模式的主要内容,如果未能解决你的问题,请参考以下文章