单例模式-base
什么是单例模式?
单例模式,即程序在运行的时候,总是只能生成一个实例。
实现思路
想要实现这一点,我们就不能让外部调用new
关键字来创建对象。因此我们想到,私有化类的构造器。
但是光是私有化类的构造器还没结束,我们还需要能够获得这个单个实例,因此我们需要在类上提供一个方法,用于获取这个实例,因此我们想到,提供一个方法来获取这个实例。
代码实现
由上面的推断,我们可以创建出一个单例模式的类,Singleton就是一个典型的单例模式的类。
/**
* @author kerwin
* @create 2024-05-08 17:21
*/
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton() {
System.out.println("生成了一个实例。");
}
public static Singleton getInstance() {
return singleton;
}
}
我们在Main方法中进行调用,查看运行结果。
/**
* @author kerwin
* @create 2024-05-08 17:30
*/
public class Main {
public static void main(String[] args) {
System.out.println("Start.");
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
if(obj1 == obj2){
System.out.println("obj1和obj2是相同的实例");
}else{
System.out.println("obj1和obj2是不同的实例");
}
System.out.println("End.");
}
}
拿着代码跑一下吧!!
运行结果如下
由上面的代码运行结果可以得出,创建的两个对象确实是同一个对象。
恭喜你!到这里,你已经掌握了单例模式的最基础的知识!怎么样?简单吧!接下来进阶学习一下!!
单例模式-plus
练习题一
在下面的TicketMaker类中,每次调用getNextTicketNumber方法都会返回1000,1001,1002…的数列。我们可以用它生成票的编号或是其他序列号。但在现在该类的实现方式下,我们可以生成多个该类的实例,导致生成的票编号无法保持唯一且连续,请修改代码,运用Singleton 模式确保只能生成一个该类的实例。
public class TicketMaker{
private int ticket = 1000;
public int getNextTicketNumber(){
return ticket++;
}
}
练习题二
请编写Triple类,实现最多只能生成3个Triple类的实例,实例编号分别为0,1,2且可以通过getInstance(int id)来获取该编号对应的实例
练习题三
某位开发人员编写了如下的singleton 类。但这并非严格的 Singleton模式。请问是为什么呢?
public class Singleton {
private static Singleton singleton = null;
private Singleton(){
System.out.println("生成了一个实例。");
}
public static Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}
答案
习题一
思路:我们只需要把TicketMaker类的构造器私有化,再将我们唯一的实例暴露出去就好啦,这是一个经典的单例模式的使用场景。
实现的TicketMaker类如下
public class TicketMaker {
private int ticket = 1000;
private static TicketMaker singleton = new TicketMaker();
private TicketMaker() {
}
public static TicketMaker getInstance(){
return singleton;
}
public synchronized int getNextTicketNumber() {
return ticket++;
}
}
让我们来用一下吧!~
public class Main1 {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(TicketMaker.getInstance().getNextTicketNumber());
}
}
}
输出结果
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
习题二
思路:我们可以使用数组或集合来创建多个Triple类的实例,在需要的时候,根据id使用数组或集合下标来进行获取。
public class Triple {
private static List<Triple> list = Arrays.asList(new Triple(),new Triple(),new Triple());
private Triple() {
}
public static Triple getInstance(int id) {
return list.get(id);
}
}
调用一下试试看!
public class Main {
public static void main(String[] args) {
Triple instance0_1 = Triple.getInstance(0);
Triple instance0_2 = Triple.getInstance(0);
if(instance0_1==instance0_2){
System.out.println("相同");
}
Triple instance1_1 = Triple.getInstance(1);
Triple instance1_2 = Triple.getInstance(1);
if(instance1_1==instance1_2){
System.out.println("相同");
}
}
}
习题三
思路:这不是一个严格的单例模式,是因为在调用getInstance
方法的时候,在多线程
几乎同时调用的情况下,则可能会创建不只一个对象,导致不满足单例模式永远只有一个对象的基本原则。
让我们仔细的探索一下吧!
我们先改进一下Singleton类,我们在调用getInstance
方法的时候进行延时,确保可以多个线程都可以在实例singleton开始为null的时候进入getInstance方法,从而多次调用new
来创建多个对象。
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
//减慢创建实例的速度
slowDown();
System.out.println("生成了一个实例");
}
public static Singleton getInstance() {
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
public static void slowDown() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
我们创建自己的线程类
public class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
public void run(){
Singleton obj = Singleton.getInstance();
System.out.println(getName()+": obj = "+obj);
}
}
在Main主类中进行调用
public class Main3{
public static void main(String[] args) {
System.out.println("Start.");
new MyThread("A").start();
new MyThread("B").start();
new MyThread("C").start();
System.out.println("end");
}
}
结果如下
Start.
end
生成了一个实例
生成了一个实例
生成了一个实例
B: obj = singleton.plus.Singleton@2591fc33
C: obj = singleton.plus.Singleton@50f6a567
A: obj = singleton.plus.Singleton@2bc3709c
我们通过延时,模拟了多个线程几乎同时进入到getInstance,结果是出现了多个不同的实例,由此可以见得,这种单例方式非严格的单例模式。
单例模式的讲解到此就结束啦,感谢阅读。💕