单例模式简介
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式结构
单例模式是关于怎样设计一个类,并使得该类只有一个实例的成熟模式,该模式的关键是将类的构造方法设置为private权限,并提供一个返回它的唯一实例的类方法。
使用场景:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
注意事项:
getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。
单例模式懒汉和饿汉实现
(1)懒汉实现
package single;
/**单例模式练习 :
*
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
三大特点:私有构造函数,静态私有成员变量,静态的共有的工厂方法。
*/
/**对于懒汉类型的安全隐患,多个线程同时访问将导致创建多个对象,该怎么办?
* 多线程会创建不同的对象,就有不同的单例对象
* 多线程访问同一个资源的安全问题,而单线程就不会
*/
public class Simplesgl {
//懒汉类型
//根据类型进行初始化,引用类型返回null,并且只能是static
private static Simplesgl instance=null;//这里是引用类型
//定义为private
private Simplesgl(){
}
/**不同的线程会创建不同的对象
* 所以对线程进行加锁synchronized
*/
public synchronized static Simplesgl newInstance(){
//进行创建唯一的对象,因为引用类型返回值为null
if(instance==null){
try {
//创建线程类
//Thread.sleep(new Random().nextInt(1000));
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance=new Simplesgl();
}
return instance;
}
}
(2)饿汉实现
package single;
/**单例模式练习 :
*
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
三大特点:私有构造函数,静态私有成员变量,静态的共有的工厂方法。
*/
public class Simplesgl2{
//饿汉类型
//根据类型进行初始化,引用类型返回null,并且只能是static
private static Simplesgl2 instance=new Simplesgl2();//这里是引用类型
//定义为private
private Simplesgl2(){
}
public static Simplesgl2 newInstance(){
//进行创建唯一的对象,因为引用类型返回值为null
// if(instance==null){
// instance=new Simplesgl();
// }
return instance;
}
}
(3)测试类
package single;
public class TestSingle {
public static void main(String[] args) {
//单例模式:永远就只是创建一个对象。
// Simplesgl sgl =new Simplesgl();
// Simplesgl sgl2=new Simplesgl();
Simplesgl sgl =Simplesgl.newInstance();
//Simplesgl sgl2=null;
// Simplesgl sgl2=Simplesgl.newInstance();
// Simplesgl sgl3=Simplesgl.newInstance();
System.out.println("*******------------*********");
new Thread(
//lambda表达式()->{}自动推导
()->{
Simplesgl sgl2=Simplesgl.newInstance();
System.out.println("lambda----sgl2:"+sgl2);
}
).start();
for(int i=0;i<20;i++)
new Thread(
//lambda表达式()->{}自动推导
()->{
Simplesgl sgl3=Simplesgl.newInstance();
System.out.println("lambda----sgl3:"+sgl3);
}
).start();
System.out.println(sgl);
// System.out.println(sgl2);
// System.out.println(sgl3);
}
}
案例实现
简介:用单例模式实现唯一的月亮。
(1)Moon类
package single;
/**
* 单例类(单件类):确保一个类只有一个实例
*/
public class Moon {
private static Moon uniqueMoon;//定义唯一的月亮
double radius;//定义月亮的半径
double distanceToEarth;//定义月亮的距离
//定义私有的构造方法,该类不会被实例化
private Moon() {
uniqueMoon = this;
radius = 1738;//月球的半径
distanceToEarth = 363300;//月球距地球的距离
}
//该方法是懒汉型,存在安全隐患,要对其加锁synchronized
public static synchronized Moon getMoon() {
//进行创建唯一的对象,引用类型返回值为null
if(uniqueMoon == null) {
uniqueMoon = new Moon();
}
return uniqueMoon;
}
//定义一个成员方法,返回信息
public String show() {
String s = "月亮的半径是" + radius + "km, 距地球是" + distanceToEarth + "km";
return s;
}
}
(2)App类
package single;
import javax.swing.*;
import java.awt.*;
public class App{
public static void main(String[] args) {
MyFrame f1 = new MyFrame("张三看月亮");
MyFrame f2 = new MyFrame("李四看月亮");
f1.setBounds(10, 10, 360, 150);
f2.setBounds(370, 10, 360, 150);
f1.validate();
f2.validate();
}
}
class MyFrame extends JFrame {
String str;
MyFrame(String title) {
setTitle(title);
Moon moon = Moon.getMoon();//得到唯一的月亮
str = moon.show();//展现信息
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
repaint();
}
public void paint(Graphics g) {
super.paint(g);
g.setFont(new Font("宋体", Font.BOLD, 14));
g.drawString(str, 5, 100);
}
}