文章目录
1.饿汉式(线程安全)
1.1饿汉式直接实例
package test;
/**
* 饿汉式
* 直接创建对象
* 1.构造器私有化
* 2.自行创建,并用静态变量保存
* 3.向外提供这个实例
* 4.强调这是一个实例,用final修饰
*/
public class SingletonTest {
public static final SingletonTest INSTANCE = new SingletonTest();
private SingletonTest(){}
public static void test(){
//如果是为了调用静态方法而创建对象,则无需创建实例对象
//但饿汉式无论需不需要都会创建实例
}
}
获取实例
public class TestSingleton1 {
public static void main(String[] args) {
SingletonTest1 s = SingletonTest1.INSTANCE;
System.out.println(s);//test.SingletonTest1@4769b07b
}
}
饿汉式:直接创建对象
- 1.构造器私有化
- 2.自行创建,并用静态变量保存
- 3.向外提供这个实例
- 4.强调这是一个实例,用final修饰
缺点
- 如果是为了调用静态方法而创建对象,则无需创建实例对象
- 但饿汉式无论需不需要都会创建实例
1.2饿汉式枚举式
public enum SingletonTest2 {
INSTANCE
}
获取实例
public class TestSingleton2 {
public static void main(String[] args) {
SingletonTest2 s = SingletonTest2.INSTANCE;
System.out.println(s);//INSTANCE
}
}
1.3饿汉式静态代码块(线程安全)
类初始化方法
<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,是线程安全的
虚拟机会保证一个类的类构造器clinit()在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的类构造器clinit(),其他线程都需要阻塞等待,直到活动线程执行clini()方法完毕。
public class SingletonTest3 {
public static final SingletonTest3 INSTANCE;
private String info;
static{
INSTANCE = new SingletonTest3("hello");
}
private SingletonTest3(String info){
this.info = info;
}
}
配置文件single.properties
info=hello
- 与直接实例差不多
- 在框架的配置文件导入会
1.4运用静态代码式创建单例导入配置文件
- 运用静态代码式创建单例
package test;
import java.io.IOException;
import java.util.Properties;
public class SingletonTest3 {
public static final SingletonTest3 INSTANCE;
private String info;
static{
try {
Properties pro = new Properties();
pro.load(SingletonTest3.class.getClassLoader().getResourceAsStream("single.properties"));
INSTANCE = new SingletonTest3(pro.getProperty("info"));
} catch (IOException e) {
throw new RuntimeException();
}
}
private SingletonTest3(String info){
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "SingletonTest3{" +
"info='" + info + '\'' +
'}';
}
}
- 调用单例
package test;
/**
* @author dongtangqiang
*/
public class TestSingleton3 {
public static void main(String[] args) {
SingletonTest3 s = SingletonTest3.INSTANCE;
System.out.println(s);//SingletonTest3{info='hello'}
}
}
- 配置文件
info=hello
2.懒汉式
2.1线程不安全,适合单线程
- 构造器私有化
- 用静态变量保存这个唯一空间
- 提供静态方法,获取这个实例对象
package test;
/**
* 懒汉式
* 延迟创建实例对象
* 1.构造器私有化
* 2.用静态变量保存这个唯一空间
* 3.提供静态方法,获取这个实例对象
*/
public class SingletonTest4 {
private static SingletonTest4 instance;
private SingletonTest4(){}
public static SingletonTest4 getInstance(){
if(instance == null){
//休眠100,验证多线程不安全
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new SingletonTest4();
}
return instance;
}
}
package test;
import java.util.concurrent.*;
public class TestSingleton4 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
SingletonTest4 s1 = SingletonTest4.getInstance();
SingletonTest4 s2 = SingletonTest4.getInstance();
System.out.println(s1 == s2);//true
System.out.println(s1);//test.SingletonTest4@4e50df2e
System.out.println(s2);//test.SingletonTest4@4e50df2e
//创建多线程验证线程不安全
Callable<SingletonTest4> c = new Callable<SingletonTest4>() {
@Override
public SingletonTest4 call() throws Exception {
return SingletonTest4.getInstance();
}
};
//线程池
ExecutorService es = Executors.newFixedThreadPool(2);
Future<SingletonTest4> f1 = es.submit(c);
Future<SingletonTest4> f2 = es.submit(c);
//Callable有返回值
SingletonTest4 s3 = f1.get();
SingletonTest4 s4 = f2.get();
//由此可以得出多线程不安全
System.out.println(s3 == s4);//false
System.out.println(s3);//test.SingletonTest4@b1bc7ed
System.out.println(s4);//test.SingletonTest4@7cd84586
es.shutdown();
}
}
2.2线程安全,适用于多线程(复杂)
- 用了synchronized保证线程安全
package test;
/**
* 懒汉式
* 延迟创建实例对象
* 1.构造器私有化
* 2.用静态变量保存这个唯一空间
* 3.提供静态方法,获取这个实例对象
*/
public class SingletonTest4 {
private static SingletonTest4 instance;
private SingletonTest4(){}
public static SingletonTest4 getInstance(){
if(instance == null){
synchronized (SingletonTest4.class){
if(instance == null){
//休眠100,验证多线程不安全
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new SingletonTest4();
}
}
}
return instance;
}
}
true
test.SingletonTest4@b1bc7ed
test.SingletonTest4@b1bc7ed
2.3静态内部类形式(线程安全)
- 在内部类被加载和初始化时,才创建INSTANCE实例对象
- 静态内部类不会随着外部类加载和初始化而初始化,它要独自加载和初始化
- 因为是在内部类加载和初始化时。创建的,因此是线程安全的
package test;
/**
* 在内部类被加载和初始化时,才创建INSTANCE实例对象
* 静态内部类不会随着外部类加载和初始化而初始化,它要独自加载和初始化
* 因为是在内部类加载和初始化时。创建的,因此是线程安全的
*/
public class SingletonTest5 {
private SingletonTest5(){}
//内部类
private static class Inner{
private static final SingletonTest5 INSTANCE = new SingletonTest5();
}
public static SingletonTest5 getInstance(){
return Inner.INSTANCE;
}
}