单例模式(Singleton)
单例模式之饿汉式
//饿汉式,类加载到内存后,就实例化一个单例,JVM保证线程安//全,简单实用,推荐使用
//缺点:不管用到与否,类装载时就完成实例化
public class Mgr01 {
//
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01() {
}
public static Mgr01 getInstance() {
return INSTANCE;
}
public static void main(String[] args) {
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1 == m2);
}
}
单例模式之懒汉式
//也称懒汉式
//虽然达到了按需初始化的目的,但是确带来了线程不安全的风险
public class Mgr03 {
private static Mgr03 INSTANCE;
//注意此处的构造方法是私有方法,所以该类不能在其他类中通过构造函数进行实例化
private Mgr03() {
}
//如果两个线程同时到达等于null这一步,然后就可能同时产生好多个对象,因此不是线程安全的
public static Mgr03 getInstance() throws InterruptedException {
if (INSTANCE == null) {
Thread.sleep(1);
INSTANCE = new Mgr03();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
try {
System.out.println(Mgr03.getInstance().hashCode());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
}
}
对懒汉式单例模式进行改进
public class Mgr04 {
private static Mgr04 INSTANCE;
private Mgr04() {
}
//在此处加上了同步锁,虽然不会发生线程不安全的情况,但是由于
//整个锁的范围是整个方法级的,因此效率不是很高
public static synchronized Mgr04 getInstance() {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
INSTANCE = new Mgr04();
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr04.getInstance().hashCode());
}).start();
}
}
}
提高懒汉式单例模式效率
public class Mgr05 {
//注意此处的关键字volatile是出于JIT可能会出现对编码重新排序的问题,使用该关键字可实现线程之间的可见性
private static volatile Mgr05 INSTANCE;
private Mgr05() {
}
//该方法不能保证线程安全性,因为此处的判断和下面判断中的
//执行代码不是保证一体的,当第一个线程执行到同步代码前,第二个线程
//执行到return语句前,此时已经产生一个对象,这时第一个线程接着执行生成一个
//新的对象,此时已经产生了两个不同的对象,所以线程不安全,但是此处把同步锁的范围变小了,相应的执行效率应该也会有所提高
public static Mgr05 getInstance() {
if (INSTANCE == null) {
synchronized (Mgr05.class) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
INSTANCE = new Mgr05();
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr05.getInstance().hashCode());
}).start();
}
}
}
解决上一个方案中出现的线程不安全的问题
//该例子是线程安全的
//该方法中使用了双重检查,在
public class Mgr06 {
private static Mgr06 INSTANCE;
private Mgr06() {
}
public static Mgr06 getInstance() {
//上面的检查是为了后面大多数的线程做判断如果为空,可以直接进行返回
if (INSTANCE == null) {
//双重检查
synchronized (Mgr06.class) {
if (INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr06.getInstance().hashCode());
}).start();
}
}
}
使用静态内部类方式的单例模式
//加载外部类的时候不会加载内部类,这样同时也可以实现懒加载,实现按需分配
public class Mgr07 {
private Mgr07() {
}
private static class Mgr07Holder {
private final static Mgr07 INSTANCE =
new Mgr07();
}
public static Mgr07 getInstance() {
return Mgr07Holder.INSTANCE;
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(() -> {
System.out.println(Mgr07.getInstance().hashCode());
}).start();
}
}
}