保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
在学习设计模式时 , 我们尽量掌握每种模式的场景 , 意义 ,以及思维模式的转化 ,而不是死记硬背代码
只生产一个实例 ,减少系统开销 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计 一个单例类,负责所有数据表的映射处理 当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
package ah.szxy.singleton;
/**
* 单例模式-饿汉式
*
* 创建一个类的对象并初始化
* 创建一个获取它的方法,返回这对象
*
* @author chy
*
*/
public class SingletonDemo1 {
//类初始化时,类加载时这个对象就被加载 ,线程安全 ,但无延迟加载优势
private static SingletonDemo1 instance=new SingletonDemo1();
//方法没有同步 ,调用效率高
public static SingletonDemo1 getInstance() {
return instance ;
}
private SingletonDemo1() { };
}
package ah.szxy.singleton;
/**
* 单例模式-懒汉式
*
* 声明一个类的对象 ,不初始化
* 创建一个获取该类的方法(线程锁) ,如果对象不为空就进行初始化,为空则直接返回
*
* @author chy
*
*/
public class SingletonDemo2 {
//类初始化时 ,不加载这个变量 .延时加载,用到再加载
private static SingletonDemo2 instance;
//synchronize 作用 :同步锁,一次只能被一个线程访问 ,且访问时,自动被挂起
//使方法同步 ,调用效率低
public static synchronized SingletonDemo2 getInstance() {
if (instance==null) {
instance=new SingletonDemo2() ;
}
return instance;
}
private SingletonDemo2() { };//私有化构造器
}
package ah.szxy.singleton;
/**
* 单例模式-静态内部类方式
*
* 创建一个静态内部类 ,内部类中创建一个类的对象并初始化
* 创建一个获取这个类的方法,通过调用内部类返回这个类的对象
*
* @author chy
*
*/
public class SingletonDemo4 {
private static class SingletonClassInstance {
private static final SingletonDemo4 instance = new SingletonDemo4();
}
public static SingletonDemo4 getInstance() {
return SingletonClassInstance.instance;
}
private SingletonDemo4() { }
}
package ah.szxy.singleton;
/**
* 单例模式-双重检测锁
*
* 先创建一个类的对象不初始化
* 静态方法没加锁 ,通过if进行判断
* 如果对象为空 ,在声明这个类是进行加上锁
* 声明的对象为空,在初始化时加锁
*
* @author chy
*
*/
public class SingletonDemo3 {
private static SingletonDemo3 instance = null;
public static SingletonDemo3 getInstance() {
if (instance == null) {
SingletonDemo3 sc;
synchronized (SingletonDemo3.class) {
sc = instance;
if (sc == null) {
synchronized (SingletonDemo3.class) {
if (sc == null) {
sc = new SingletonDemo3();
}
}
instance = sc;
}
}
}
return instance;
}
private SingletonDemo3() {
}
}
package ah.szxy.singleton;
/**
* 单例模式-枚举式
*
* 声明一个enum类型的类
* 声明一个枚举元素
* 声明一个枚举类型的方法,根据需要添加内容
*
* @author 曹海洋
*
*/
public enum SingletonDemo5 {
//枚举元素 ,本身就是单例对象
INSTANCE;
//添加自定义操作
public void SingletonOperator() {
}
}
测试类
package ah.szxy.singleton;
import java.util.concurrent.CountDownLatch;
public class Client {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
int threadNum=10;//线程计数器
//CountDownLatch是一个同步的辅助类,允许一个或多个线程一直等待,直到其它线程完成它们的操作。
CountDownLatch countDownLatch = new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
new Thread(new Runnable() {//创建了一个线程
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
SingletonDemo4 o = SingletonDemo4.getInstance();
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await();//主线程阻塞后,直到计数器变为0,才会继续相信执行
long end =System.currentTimeMillis();
System.out.println("总时长"+(end-start));
}
}
CountDownLatch 同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一 个或多个线程一直等待。 • countDown() 当前线程调此方法,则计数减一(建议放在 finally里执行) • await(), 调用此方法会一直阻塞当前线程,直到计时器的值为0
测试结果 会因为每台主机的性能原因而不同, 这里只做参考
重点掌握饿汉式 , 懒汉式 ,静态内部类式