介绍
单例模式:采用特定的方法导致某个类,只有一个对象实例,并且该类只提供一个取得其对象实例的方法。
创建单例模式:总共有八种创建单例模式的方法。
单例模式保证了系统中只有一个对象,对于需要频繁创建和销毁的对象。使用单例模式可以提高系统性能。
单例模式创建的方法是对象名加姓名。而不是通过new。
使用场景:频繁创建和销毁的对象。比如:工具类对象,频繁访问数据库的文件对象
饿汉式(静态常量)
- 构造器私有化
- 类的内部创建对象
- 向外暴露一个静态公共方法
public class Main {
public static void main(String[] args) {
Single s = Single.getSingle();
Single s1 = Single.getSingle();
System.out.println(s == s1);
}
}
class Single {
private final static Single s = new Single();
private Single(){
}
public static Single getSingle(){
return s;
}
}
- 优点:类在装载的时候就已经拿到了类的实例化,避免了线程同步的问题。
- 缺点:在类加载就已经实例化了,没有达到 懒加载 的效果,如果没有用到这个实例那么就浪费了内存。
- 这个方法避免了类的多线程同步问题,但是可能会出现内存浪费
饿汉式(静态代码块)
public class Main {
public static void main(String[] args) {
Single s = Single.getSingle();
Single s1 = Single.getSingle();
System.out.println(s == s1);
}
}
class Single {
private static Single s ;
static {
s = new Single();
}
private Single(){
}
public static Single getSingle(){
return s;
}
}
- 在类加载是通过静态代码块,对类进行了实例化。但是依然会有内存浪费的现象。
懒汉式(线程不安全)
public class Main {
public static void main(String[] args) {
Single s = Single.getSingle();
Single s1 = Single.getSingle();
System.out.println(s == s1);
}
}
class Single {
private static Single s ;
private Single(){
}
public static Single getSingle(){
if(s == null){
s = new Single();
}
return s;
}
}
- 我们将对象实例化的过程放入对外暴露的静态方法中。
- 确实可以起到懒加载的效果。但是只能用于单线程。
- 但是如果在多线程下,多个线程同步判断 if(s == null)为true时,会对使其创建多个实例。
懒汉式(线程安全,同步方法)
public class Main {
public static void main(String[] args) {
Single s = Single.getSingle();
Single s1 = Single.getSingle();
System.out.println(s == s1);
}
}
class Single {
private static Single s ;
private Single(){
}
public static synchronized Single getSingle(){
if(s == null){
s = new Single();
}
return s;
}
}
- 使用synchronized对同步线程进行处理
- 效率低,每个实例多需要调用getSingle方法时都要进行同步,但是这个只需要执行一次实例化代码就够了。
懒汉式(线程安全,同步代码块)
public class Main {
public static void main(String[] args) {
Single s = Single.getSingle();
Single s1 = Single.getSingle();
System.out.println(s == s1);
}
}
class Single {
private static Single s ;
private Single(){
}
public static synchronized Single getSingle(){
if(s == null){
synchronized(Single.class) {s = new Single();}
}
return s;
}
}
1.虽然这里已经实现了在代码块中实现了线程安全,但是if(s == null)没有实现线程安全。
双重检查
线程对volatile变量的修改会立刻被其他线程所感知,即不会出现数据脏读的现象,从而保证数据的“可见性”。
public class Main {
public static void main(String[] args) {
Single s = Single.getSingle();
Single s1 = Single.getSingle();
System.out.println(s == s1);
}
}
class Single {
private static volatile Single s ;
private Single(){
}
public static synchronized Single getSingle(){
if(s == null){
synchronized(Single.class) {
if(s==null){
s = new Single();
}
}
}
return s;
}
}
静态内部类
public class Main {
public static void main(String[] args) {
Single s = Single.getSingle();
Single s1 = Single.getSingle();
System.out.println(s == s1);
}
}
class Single {
private static volatile Single s ;
private Single(){
}
private static class SingleInstance{
private static final Single single = new Single();
}
public static synchronized Single getSingle(){
return SingleInstance.single;
}
}
静态内部类实现了懒加载,在装载类的时候是安全的所以也解决了线程同步问题。
枚举
public class Main {
public static void main(String[] args) {
Single s = Single.INSTANCE;
Single s1 = Single.INSTANCE;
System.out.println(s == s1);
}
}
enum Single {
INSTANCE;
public void method(){
}
}
1。可以使用。