1.懒汉式
package com.example.starter;
/***
* 懒汉式
*/
public class SilgletonDemo1 {
private static SilgletonDemo1 instance = null;
private SilgletonDemo1(){
System.out.println(Thread.currentThread().getName()+"构造方法调用");
}
public static SilgletonDemo1 getInstance(){
if(instance == null){
instance = new SilgletonDemo1();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SilgletonDemo1.getInstance();
}).start();
}
}
}
结果:正常情况下 构造方法只会调用一次 但是 此程序调用了4次
2.懒汉式 加synchronized
package com.example.starter;
/***
* 懒汉式
*/
public class SilgletonDemo1 {
private static SilgletonDemo1 instance = null;
private SilgletonDemo1(){
System.out.println(Thread.currentThread().getName()+"构造方法调用");
}
public synchronized static SilgletonDemo1 getInstance(){
if(instance == null){
instance = new SilgletonDemo1();
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SilgletonDemo1.getInstance();
}).start();
}
}
}
结果:结果正常了 但高并发模式下 性能低下
3.双端检测
方式3优于方式2 但还是会出问题,因为指令重排:
package com.example.starter;
/***
* 懒汉式
*/
public class SilgletonDemo1 {
private static SilgletonDemo1 instance = null;
private SilgletonDemo1(){
System.out.println(Thread.currentThread().getName()+"构造方法调用");
}
public static SilgletonDemo1 getInstance(){
if(instance == null){
synchronized (SilgletonDemo1.class){
if(instance == null){
instance = new SilgletonDemo1();
}
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SilgletonDemo1.getInstance();
}).start();
}
}
}
4.加volatile 推荐使用
此方式是比较完美的解决方案
package com.example.starter;
/***
* 懒汉式
*/
public class SilgletonDemo1 {
private volatile static SilgletonDemo1 instance = null;
private SilgletonDemo1(){
System.out.println(Thread.currentThread().getName()+"构造方法调用");
}
public static SilgletonDemo1 getInstance(){
if(instance == null){
synchronized (SilgletonDemo1.class){
if(instance == null){
instance = new SilgletonDemo1();
}
}
}
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SilgletonDemo1.getInstance();
}).start();
}
}
}
5.懒汉式(静态常量) 推荐使用
这种写法比较简单,就是在类装载的时候就完成实例化。避免了线程同步问题
缺点:在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费
package com.example.starter;
/**
* 饿汉式
*/
public class SilgletonDemo2 {
private static SilgletonDemo2 instance = new SilgletonDemo2();
private SilgletonDemo2(){
System.out.println(Thread.currentThread().getName()+"构造方法调用");
}
public static SilgletonDemo2 getInstance(){
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SilgletonDemo2.getInstance();
}).start();
}
}
}
6.饿汉式(静态代码块) 推荐使用 优缺点同5
package com.example.starter;
/**
* 饿汉式
*/
public class SilgletonDemo2 {
private static SilgletonDemo2 instance ;
static {
instance = new SilgletonDemo2();
}
private SilgletonDemo2(){
System.out.println(Thread.currentThread().getName()+"构造方法调用");
}
public static SilgletonDemo2 getInstance(){
return instance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
SilgletonDemo2.getInstance();
}).start();
}
}
}