什么是Singleton?
singleton:在java中指的是单例设计模式,他是软件开发常用的设计模式之一
单:唯一
例:实例
单例设计模式:即某个类在整个系统中只能有一个实例对象可获取和使用的代码模式
要点
一是某个类只有一个实例:
构造器私有化
二是它必须自行创建这个实例:
含有一个该类的静态变量来保存这个实例:
三是它必须自行向整个系统提供这个实例:
对外提供获取该实例对象的方式: 1.直接暴露 2.用静态变量get方法获取
几种常见形式
一、饿汉式:直接创建对象,不存在线程安全问题
1.直接实例化恶汉式(简洁直观)
/*
*恶汉式
*直接创建这个单例,不管你需不需要
* 用静态变量保存
* 用final修饰这个变量,强调这是一个单例
* 构造器私有
* 向外提供这个实例
*/
public class Singletonl {
public static final Singletonl SINGLETONL = new Singletonl();
private Singletonl(){
}
}
2.枚举型(最简洁)
/*
*枚举类型
*/
public enum Singleton2 {
SINGLETON
}
3.静态 代码块饿汉式(适合复杂实例化)
//简单
public class Singleton3 {
public static final Singleton3 INSTANCE ;
static{
INSTANCE = new Singleton3();
}
private Singleton3(){
}
}
//==================================================================================/
//复杂
public class Singleton3 {
public static final Singleton3 SINGLETONL ;
private String info;
static{
try {
Properties pro = new Properties();
//读取配置文件singleton.properties中的常量info
pro.load(Singleton3.class.getClassLoader().getResourceAsStream("singleton.properties"));
SINGLETONL = new Singleton3(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException();
}
}
private Singleton3(String info){
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Singleton3{" +
"info='" + info + '\'' +
'}';
}
}
测试:两种方式都一样,一个输出这个类,一个输出这个静态变量
//直接实例化饿汉式方法调用
public class SingletonTest {
public static void main(String[] args) {
Singletonl s = Singletonl.SINGLETONL;
System.out.print(s);
}
}
//输出结果:com.mybitis.plus.singletonl.Singletonl@681a9515
//测试枚举型饿汉式方法调用
public class SingletonTest {
public static void main(String[] args) {
Singleton2 s = Singleton2.SINGLETON;
System.out.print(s);
}
}
//输出结果:SINGLETON
//静态 代码块饿汉式
public class SingletonTest {
public static void main(String[] args) {
Singleton3 s = Singleton3.SINGLETONL;
System.out.print(s);
}
}
//输出结果:com.mybitis.plus.singletonl.Singletonl@681a9515 (或 info的值)
二、懒汉式 :延迟创建对象
1.线程不安全(适用于单线程)
/*
*懒汉式,延迟创建实例
* 1.私有化构造器
* 2.用一个静态变量保存这个实例
* 3.提供一个静态方法,获取这个实例对象
*/
public class Singleton4 {
private static Singleton4 INSTANCE;
private Singleton4(){
}
public static Singleton4 getINSTANCE(){
if (INSTANCE == null){
try {
// 测试线程安不安全
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton4();
}
return INSTANCE;
}
}
测试:
public class TestSingleton {
public static void main(String[] args) {
// Singleton4 s1= Singleton4.getINSTANCE();
// Singleton4 s2= Singleton4.getINSTANCE();
// System.out.println(s1==s2); //输出true
//创建多线程方法
Callable<Singleton4> c = new Callable<Singleton4>() {
@Override
public Singleton4 call() throws Exception {
return Singleton4.getINSTANCE();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton4> f1 = es.submit(c);
Future<Singleton4> f2 = es.submit(c);
Singleton5 s1 = f1.get();
Singleton5 s2 = f2.get();
System.out.println(s1==s2);
}
}
//输出:false
2.线程安全(适用于多线程)
对其加锁了,来确保线程安全,用synchronized做修饰
/*
*懒汉式,延迟创建实例
* 1.私有化构造器
* 2.用一个静态变量保存这个实例
* 3.提供一个静态方法,获取这个实例对象
*/
public class Singleton5 {
private static Singleton5 INSTANCE;
private Singleton5(){
}
public static Singleton5 getINSTANCE(){
if (INSTANCE == null){//加一层判断提高性能
synchronized(Singleton5.class){
if (INSTANCE == null){
try {
// 测试线程安不安全
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Singleton5();
}
}
}
return INSTANCE;
}
}
测试
public class TestSingleton {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建多线程方法
Callable<Singleton5> c = new Callable<Singleton5>() {
@Override
public Singleton5 call() throws Exception {
return Singleton5.getINSTANCE();
}
};
ExecutorService es = Executors.newFixedThreadPool(2);
Future<Singleton5> f1 = es.submit(c);
Future<Singleton5> f2 = es.submit(c);
Singleton5 s1 = f1.get();
Singleton5 s2 = f2.get();
System.out.println(s1==s2);
}
}
//输出:true
3.静态内部类形式(适用于多线程)
/*
*在静态类被加载和初始化时,才创建INSTANCE实例对象
* 静态内部类不会自动随着外部类的加载和初始化而初始化,他是单独去加载初始化的
* 因为在内部类加载和初始化时,创建的,因此线程是安全的
*/
public class Singleton6 {
private Singleton6(){
}
private static class Inner{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return Inner.INSTANCE;
}
}
总结:
如果是饿汉式则枚举型更简单
如果是懒汉式则内部静态类最简单