JAVA设计模式课堂整理(代码都是maven引入junit包)
pom文件:
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
单例模式属于设计模式中的创建型模式,研究的是对象创建问题
单例模式
单例模式是确保某─个类只有一个实例,而且自行实例化并向整个系统提供这个实例,
注意:某个类只能有一个实例,类必须自行创建这个实例,以公共、统一的方式向整个系统提供这个实例。
饿汉式单例模式:
线程安全,调用时间效率较高,不支持延迟加载
Java类:
package org.tawil.demo.singleton_pattern.hungry;
//1/本类一旦初始化(静态属性随类初始化赋初值),对象即被创建,是立即加载(饿汉式)
public class HungrySingleton{
public static void fn(){
}
//2.定义一个私有的本类型的静态属性,并直接创建本类对象赋值,而且仅能在类的初始化时赋值一次
private static HungrySingleton instance = new HungrySingleton () ;
//3.提供公有的静态的获取对象实例的方法
public static HungrySingleton getInstance () {
return instance;
}
//1.构造方法私有化
private HungrySingleton(){
System.out.println("hungrysingleton is be ready");
}
}
测试类
import org.junit.Test;
import org.tawil.demo.singleton_pattern.hungry.HungrySingleton;
public class singleton_patternTest {
//测试饥汉式
@Test
public void hungryTest(){
HungrySingleton.fn ( );// Hungrysingleton第一次被使用
System.out.println( "-----------------------------------") ;
HungrySingleton instance1= HungrySingleton.getInstance() ;
HungrySingleton instance2 = HungrySingleton.getInstance() ;
System.out.println(instance1 == instance2);
}
}
懒汉式单例模式:
线程安全(显示使用同步机制),调用时间效率较低,支持延迟加载
Java类:
package org.tawil.demo.singleton_pattern.lazy;
public class LazySingleton {
public static void fn (){}
//此处不赋初始值
private static LazySingleton instance;
public static LazySingleton getInstance() {
synchronized (LazySingleton.class) {
if (instance == null) {
//如果没有引入同步机制,当一个线程运行到这儿的时候,另一个线程可能刚好在执行if(instance == null)
// 结果两个线程都进入了本if分支
instance = new LazySingleton();
}
return instance;
}
}
private LazySingleton() {
System.out.println("lazysingleton is be ready! ");
}
}
测试类:
import org.junit.Test;
import org.tawil.demo.singleton_pattern.lazy.LazySingleton;
public class singleton_patternTest {
//测试懒汉式
@Test
public void lazyTest(){
LazySingleton.fn ( );// Hungrysingleton第一次被使用
System.out.println( "-----------------------------------") ;
LazySingleton instance1= LazySingleton.getInstance() ;
LazySingleton instance2 = LazySingleton.getInstance() ;
System.out.println(instance1 == instance2);
}
//测试懒汉式多线程
@Test
public void lazysTest() throws InterruptedException {
Thread t1 = new Thread(){
@Override
public void run(){
LazySingleton.getInstance();
}
};
Thread t2 = new Thread(){
@Override
public void run(){
LazySingleton.getInstance();
}
};
t1.start();
t2.start();
t1.join();//测试线程等待t1线程结束,再继续进行t2-join ();
t2.join();//测试线程等待t2线程结束,再继续进行
//注: junit测试线程结束时,会调用system.exit(0),导致整个系统终止
}
}
懒汉式单例模式升级–双检锁单例模式:
在懒汉式中:
//此处不赋初始值
private static LazySingleton instance;
public static LazySingleton getInstance() {
synchronized (LazySingleton.class) {
if (instance == null) {
//如果没有引入同步机制,当一个线程运行到这儿的时候,另一个线程可能刚好在执行if(instance == null)
// 结果两个线程都进入了本if分支
instance = new LazySingleton();
}
return instance;
}
如果interest为null,仍会进入此同步锁,等待同步锁,会降低效率
因此在这个外部再加一个检测锁:
if (instance == null) {}
此时如果interest不为null,不会进入此同步锁,不会等待同步锁,不会降低效率
instance = new DoubleCheckSingleton();
执行步骤
1.在堆中分配空间(只要分配空间,引用即实际存在)
2.对象初始化
3.将对象的引用赋给变量instance
但有些编译器为提高效率会进行指令重排,将2,3颠倒。
此时:有可能某个线程被引用结果对象初始化未完成运行错误。
因此要避免指令重排
**使用volatile修饰变量**,禁止指令重排
Java类:
package org.tawil.demo.singleton_pattern.DoubleCheckSingleton;
//双检索式
public class DoubleCheckSingleton {
public static void fn (){}
//此处不赋初始值
//此处使用volatile修饰变量
private static volatile DoubleCheckSingleton instance;
public static DoubleCheckSingleton getInstance() {
if (instance == null) {//第一重检测锁锁
synchronized (DoubleCheckSingleton.class) {
if (instance == null) {//第二重检测锁
instance = new DoubleCheckSingleton();
}
}
}
return instance;
}
private DoubleCheckSingleton() {
System.out.println("DoubleCheckSingleton is be ready! ");
}
}
测试类类似懒汉式:
//测试双检锁式
@Test
public void DoubleCheckSingletonTest(){
DoubleCheckSingleton.fn ( );// Hungrysingleton第一次被使用
System.out.println( "-----------------------------------") ;
DoubleCheckSingleton instance1= DoubleCheckSingleton.getInstance() ;
DoubleCheckSingleton instance2 = DoubleCheckSingleton.getInstance() ;
System.out.println(instance1 == instance2);
}
静态内部类方式的单例模式:
线程安全,调用时间效率较高,支持延迟加载双重检测锁式单例模式:线程安全、调用时间效率较高,支持延迟加载
Java类
package org.tawil.demo.singleton_pattern.StaticInnerSingleton;
public class StaticInnerSingleton {
public static void fn (){}
private static class Inner{
private static StaticInnerSingleton instance = new StaticInnerSingleton();
}
public static StaticInnerSingleton getInstance(){
return Inner.instance;
}
private StaticInnerSingleton(){
System.out.println("StaticInnerSingleton is be ready!");
};
}
测试类:
//测试静态内部锁式
@Test
public void StaticInnerSingletonTest(){
StaticInnerSingleton.fn ( );// Hungrysingleton第一次被使用
System.out.println( "-----------------------------------") ;
StaticInnerSingleton instance1= StaticInnerSingleton.getInstance() ;
StaticInnerSingleton instance2 = StaticInnerSingleton.getInstance() ;
System.out.println(instance1 == instance2);
}
枚举方式的单例模式:
线程安全、调用时间效率较高,立即加载
Java类:
package org.tawil.demo.singleton_pattern.Enum;
public enum EnumSingleton {
instance;//枚举常量,天然单例,立即加载(类似饿汉式)
private EnumSingleton(){
System.out.println("枚举式单例对象创建了!");
}
public static void fn(){}
public void func(){
System.out.println("func================>");
}
}
测试类:
@Test
public void 测试枚举式单例模式(){
EnumSingleton.fn();
System.out.println("-------------------------------");
System.out.println(EnumSingleton.instance == EnumSingleton.instance);
EnumSingleton.instance.func();
}
总结
单例模式 | 特点 |
---|---|
饿汉式 | 线程安全,调用时间效率较高,不支持延迟加载 |
懒汉式 | 线程安全(显示使用同步机制),调用时间效率较低,支持延迟加载 |
静态内部类 | 线程安全,调用时间效率较高,支持延迟加载 |
双重检测锁式 | 线程安全、调用时间效率较高,支持延迟加载 |
枚举式 | 线程安全、调用时间效率较高,立即加载 |