1、 使用场景:保证一个类仅有一个实例,并提供一个访问它的全局访问点。Spring 中的单例模式提供了全局的访问点BeanFactory。Spring 下默认的Bean 均为单例。
工厂本身是单例、配置文件、日历、获取数据源、IOC 容器。Listener自身是单例
2、 分类:饿汉式、懒汉式、注册式、序列化。一般采用饿汉式,若对资源十分在意可以采用静态内部类,不建议采用懒汉式及双重检测。
饿汉式 (线程安全----静态变量)
饿汉式(线程安全----静态代码块)
懒汉式(线程不安全----不添加锁机制)
懒汉式(方法同步----添加同步锁)
懒汉式(线程安全----同步代码块)
双重检查
静态内部类
枚举
/**
* 饿汉式 (线程安全----静态变量)
*/
public class Singleton {
private final static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
/**
* 饿汉式(线程安全----静态代码块)
*/
public class SingletonStaticBlock {
private static SingletonStaticBlock instance;
static{
instance = new SingletonStaticBlock();
}
public static SingletonStaticBlock getInstance(){
return instance;
}
}
import java.util.concurrent.CountDownLatch;
public class ThreadSafeTest {
public static void main(String[] args) {
int count = 200;
CountDownLatch countDownLatch = new CountDownLatch(count);
long start = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
new Thread(){
@Override
public void run() {
try{
countDownLatch.await();
//Object obj = Singleton.getInstance();//饿汉式 (线程安全----静态变量)
//Object obj = SingletonStaticBlock.getInstance(); //饿汉式(静态代码块----线程安全)
Object obj = Singleton.getInstance();//懒汉式(线程不安全----不添加锁机制)
System.out.println(Thread.currentThread().getName()+ ":" + obj);
}catch (Exception e){
e.printStackTrace();
}
}
}.start();
countDownLatch.countDown();
}
long end = System.currentTimeMillis();
System.out.println("总耗时:" + (end - start));
}
}
/**
* 懒汉式(线程不安全----不添加锁机制)
*/
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
/**
* 懒汉式(方法同步----添加同步锁)
*/
public class SingletonSync {
private static SingletonSync instance;
private SingletonSync(){}
public static synchronized SingletonSync getInstance(){
if(instance == null){
instance = new SingletonSync();
}
return instance;
}
}
/**
* 懒汉式(线程安全----同步代码块)
*/
public class SingletonSyncBlock {
private static SingletonSyncBlock instance;
private SingletonSyncBlock(){}
public static SingletonSyncBlock getInstance(){
if(instance == null){
synchronized (SingletonSyncBlock.class){
instance = new SingletonSyncBlock();
}
}
return instance;
}
}
/**
* 双重检查
*/
public class SingletonSyncBlock2 {
private static SingletonSyncBlock2 instance;
private SingletonSyncBlock2(){}
public static SingletonSyncBlock2 getInstance(){
if(instance == null){
synchronized (SingletonSyncBlock2.class){
if(instance == null) {
instance = new SingletonSyncBlock2();
}
}
}
return instance;
}
}
静态内部类方式
/**
* 静态内部类
*/
public class SingletonStaticClass {
private SingletonStaticClass(){}
private static class SingletonInstance{
private static final SingletonStaticClass INSTANCE = new SingletonStaticClass();
}
public static SingletonStaticClass getInstance(){
return SingletonInstance.INSTANCE;
}
}
public class SingletonStaticClassTest {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for (int i = 0; i < 200;i ++) {
Object obj = SingletonStaticClass.getInstance();
System.out.println(obj);
}
long end = System.currentTimeMillis();
System.out.println("总耗时:" + (end - start));
}
}
public class LazyThree {
private boolean initialized = false;
//默认使用LazyThree的时候,会先初始化内部类
//如果没使用的话,内部类是不加载的
private LazyThree(){
synchronized (LazyThree.class){
if(initialized == false){
initialized = !initialized;
}else{
throw new RuntimeException("单例已被侵犯");
}
}
}
public static final LazyThree getInstance(){
return LazyHolder.LAZY; //在返回结果以前,一定会先加载内部类
}
//默认不加载
private static class LazyHolder{
private static final LazyThree LAZY = new LazyThree();
}
}
public class LazyThreeTest {
public static void main(String[] args) {
try{
Class<?> clazz = LazyThree.class;
Constructor c = clazz.getDeclaredConstructor(null);
c.setAccessible(true);
Object o1 = c.newInstance();
Object o2 = c.newInstance();
System.out.println(o1 == o2);
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 枚举
*/
public enum SingletonEnum {
INSTANCE;
}
/**
* 序列化
*/
public class Seriable implements Serializable {
private Seriable(){}
private static final Seriable INSTANCE = new Seriable();
public static Seriable getInstance(){
return INSTANCE;
}
private Object readSolved(){
return INSTANCE;
}
}
public class SeriableTest {
public static void main(String[] args) {
Seriable s1 = Seriable.getInstance();
Seriable s2 = null;
FileOutputStream fos = null;
try{
fos = new FileOutputStream("Seriable0901.abc");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s1);
oos.flush();
oos.close();
File file;
FileInputStream fis = new FileInputStream("Seriable0901.abc");
ObjectInputStream ois = new ObjectInputStream(fis);
s2 = (Seriable) ois.readObject();
fis.close();
System.out.println(s1 == s2);
}catch (Exception e){
e.printStackTrace();
}
}
}