单例模式
单例模式,保持对象的唯一性。
私有构造方法,提供一个返回具体对象的方法。
对象在使用前已经被创建好,所以无论怎样调用,返回的都是同一个对象,所以是线程安全的
public class EagerSingleton {
/**
* 饿汉式直接初始化
*/
private static EagerSingleton instance = new EagerSingleton();
public static EagerSingleton getInstance() {
return instance;
}
private EagerSingleton() {
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> System.out.println(EagerSingleton.getInstance().hashCode())).start();
}
}
}
结果
355159803
355159803
355159803
355159803
355159803
355159803
355159803
355159803
355159803
355159803
什么时候使用什么时候创建对象,多线程下调用无法保证对象唯一
public class LazySingleton {
public static LazySingleton getInstance() {
try {
if (null == instance) {
Thread.sleep(1000);
instance = new LazySingleton();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
private static LazySingleton instance = null;
private LazySingleton() {
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> System.out.println(LazySingleton.getInstance().hashCode())).start();
}
}
}
结果
1184554318
1750416013
1294123621
1516133987
1184554318
1831557028
640934955
21895028
2034349848
1736289754
将返回对象的方法加synchronized修饰成同步方法,这样可以保证对象的唯一性,但是整个方法都加了同步,所以效率会降低。
public class LazySingletonSynchronizedMethod {
public synchronized static LazySingletonSynchronizedMethod getInstance() {
if (null == instance) {
try {
Thread.sleep(1000);
instance = new LazySingletonSynchronizedMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return instance;
}
private static LazySingletonSynchronizedMethod instance = null;
private LazySingletonSynchronizedMethod() {
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> System.out.println(LazySingletonSynchronizedMethod.getInstance().hashCode())).start();
}
}
}
结果
1184554318
1184554318
1184554318
1184554318
1184554318
1184554318
1184554318
1184554318
1184554318
1184554318
synchronized修饰方法效率降低,改为修饰创建对象的代码块,比直接修饰方法效率会好一些,但是效率同样也会降低
public class LazySingletonSynchronizedBlock {
public static LazySingletonSynchronizedBlock getInstance() {
try {
synchronized (LazySingletonSynchronizedBlock.class) {
if (null == instance) {
Thread.sleep(1000);
instance = new LazySingletonSynchronizedBlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
private static LazySingletonSynchronizedBlock instance = null;
private LazySingletonSynchronizedBlock() {
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> System.out.println(LazySingletonSynchronizedBlock.getInstance().hashCode())).start();
}
}
}
结果
375869755
375869755
375869755
375869755
375869755
375869755
375869755
375869755
375869755
375869755
用synchronized关键字修饰代码块,同时使用volatile来保证可见性
public class LazySingletonDoubleCheckLock {
public static LazySingletonDoubleCheckLock getInstance() {
try {
if (null == instance) {
Thread.sleep(1000);
synchronized (LazySingletonDoubleCheckLock.class) {
if (null == instance) {
instance = new LazySingletonDoubleCheckLock();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
private volatile static LazySingletonDoubleCheckLock instance = null;
private LazySingletonDoubleCheckLock() {
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> System.out.println(LazySingletonDoubleCheckLock.getInstance().hashCode())).start();
}
}
}
结果
21895028
21895028
21895028
21895028
21895028
21895028
21895028
21895028
21895028
21895028
public class StaticInnerClassSingleton {
public static StaticInnerClassSingleton getInstance() {
return StaticInnerClassSingletonHandler.instance;
}
private StaticInnerClassSingleton() {
}
private static class StaticInnerClassSingletonHandler {
private static StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
System.out.println(StaticInnerClassSingleton.getInstance().hashCode());
}).start();
}
}
}
public class StaticBlockSingleton {
private static StaticBlockSingleton instance = null;
static {
instance = new StaticBlockSingleton();
}
private StaticBlockSingleton() {
}
public static StaticBlockSingleton getInstance() {
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
System.out.println(StaticBlockSingleton.getInstance().hashCode());
}).start();
}
}
}
ublic enum SingletonEnum {
INSTANCE;
private Singleton instance;
SingletonEnum() {
System.out.println("只会调用一次");
instance = new Singleton();
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
System.out.println(SingletonEnum.INSTANCE.hashCode());
}).start();
}
}
}
class Singleton{
}
总结
单例模式的实现大体分为两类
- 调用前初始化对象,调用方法时返回这个初始化好的对象,线程安全
- 调用时初始化对象,线程不安全,所以需要增加代码来保证线程安全