采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)
new
创建对象)getInstance
方法)public class HungryMan {
public static void main(String[] args) {
HungryMan instance1 = HungryMan.getInstance();
HungryMan instance2 = HungryMan.getInstance();
System.out.println(instance1 == instance2); // true
}
// 1.构造器私有化
private HungryMan(){}
// 2.类的内部创建对象
private final static HungryMan instance = new HungryMan();
// 3.向外暴露一个静态的公共方法
public static HungryMan getInstance(){
return instance;
}
}
getInstance
方法,导致类装载有很多方式),没有达到Lazy Loading
的效果public class HungryMan {
public static void main(String[] args) {
HungryMan instance1 = HungryMan.getInstance();
HungryMan instance2 = HungryMan.getInstance();
System.out.println(instance1 == instance2); // true
}
// 1.构造器私有化
private HungryMan(){}
// 2.类的内部创建对象
private final static HungryMan instance;
static {
instance = new HungryMan();
}
// 3.向外暴露一个静态的公共方法
public static HungryMan getInstance(){
return instance;
}
}
static
静态代码块,都是在一个叫clinit()
的方法里面完成clinit()
代码在多线程并发的时候,只会有一个线程可以访问到,其他的线程都需要等待getInstance
方法,还有很多导致类装载的方式),没有达到Lazy Loading
的效果用到实例采取创建
public class LazyMan1 {
public static void main(String[] args) {
LazyMan1 instance1 = LazyMan1.getInstance();
LazyMan1 instance2 = LazyMan1.getInstance();
System.out.println(instance1 == instance2); // true
}
private static LazyMan1 instance;
private LazyMan1() {}
// 提供一个静态的公共方法,使用到该方法才去创建instance
public static LazyMan1 getInstance() {
if (instance == null) {
instance = new LazyMan1();
}
return instance;
}
}
Lazy Loading
的效果if (singleton == null)
判断语句块,还未来得及往下执行。另一个线程也通过了这个判断语句,这时便会产生多个实例)public class LazyMan3 {
public static void main(String[] args) {
LazyMan3 instance1 = LazyMan3.getInstance();
LazyMan3 instance2 = LazyMan3.getInstance();
System.out.println(instance1 == instance2); // true
}
private static LazyMan3 instance;
private LazyMan3() {}
// 提供一个静态的公共方法,但是使用synchronized代码块,使用到该方法才去创建instance
public static LazyMan3 getInstance() {
if (instance == null) {
synchronized (LazyMan3.class) {
instance = new LazyMan3();
}
}
return instance;
}
}
Lazy Loading
的效果public class LazyMan2 {
public static void main(String[] args) {
LazyMan2 instance1 = LazyMan2.getInstance();
LazyMan2 instance2 = LazyMan2.getInstance();
System.out.println(instance1 == instance2); // true
}
private static LazyMan2 instance;
private LazyMan2() {}
// 提供一个静态的公共方法,但是使用synchronized加在类上,使用到该方法才去创建instance
public static synchronized LazyMan2 getInstance() {
if (instance == null) {
instance = new LazyMan2();
}
return instance;
}
}
getInstance
方法都要进行同步public class DoubleCheck {
public static void main(String[] args) {
DoubleCheck instance1 = DoubleCheck.getInstance();
DoubleCheck instance2 = DoubleCheck.getInstance();
System.out.println(instance1 == instance2); // true
}
private static volatile DoubleCheck instance;
private DoubleCheck() {}
// 提供一个静态的公共方法,加入双重检查代码,使用到该方法才去创建instance
public static synchronized DoubleCheck getInstance() {
if (instance == null) {
synchronized (DoubleCheck.class) {
if (instance == null) {
instance = new DoubleCheck();
}
}
}
return instance;
}
}
实例化代码只用执行一次,后面再次访问时,判断
if (singleton == null)
,如果不为空直接return
实例化对象,避免的反复进行方法同步
public class StaticInnerClass {
public static void main(String[] args) {
StaticInnerClass instance1 = StaticInnerClass.getInstance();
StaticInnerClass instance2 = StaticInnerClass.getInstance();
System.out.println(instance1 == instance2); // true
}
private StaticInnerClass() {}
private static class SingtleonInstance {
private static final StaticInnerClass INSTANCE = new StaticInnerClass();
}
// 提供一个静态的公共方法,使用到该方法才去创建instance
public static StaticInnerClass getInstance() {
return SingtleonInstance.INSTANCE;
}
}
StaticInnerClass
类被装载时并不会立即实例化,而是在调用getInstance
方法,才会装载SingletonInstance
类,进而完成StaticInnerClass
的实例化public class Enum {
public static void main(String[] args) {
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1 == instance2); // true
}
}
enum Singleton{
INSTANCE
}
java.lang.Runtime
,它采用饿汉式public class Runtime {
private static final Runtime currentRuntime = new Runtime();
public static Runtime getRuntime() {
return currentRuntime;
}
private Runtime() {}
}
https://www.bilibili.com/video/BV1G4411c7N4?p=29-38