概念:
? ? ? ??
采取一定的方式保证整个软件系统,对某个类只能存在一个对象实例该类提供一个取得对象实例方法
饿汉式(静态常量)
import java.io.File;
import java.io.IOException;
class Person{
private final static Person instance = new Person();
//私有化 构造 防止外部 new 对象
private Person(){
}
//对外提供静态方法 获取对象
public static Person Getinstance(){
return instance;
}
}
public class MainApp {
public static void main(String[] args) {
Person getinstance = Person.Getinstance();
Person getinstance1 = Person.Getinstance();
System.out.println(getinstance == getinstance1);//true
}
}
这种方式优缺点
优点:这种方法比较简单,类装载的时候就完成实例化,避免线程同步问题
缺点:这种在类装载的时候完成初始化,如果是没有用到,则浪费内存,这种单例模式可以,但是可能浪费内存
饿汉式(静态代码块)
class Person{
private static Person instance;
//私有化 构造 防止外部 new 对象
private Person(){
}
static {
instance = new Person();
}
//对外提供静态方法 获取对象
public static Person Getinstance(){
return instance;
}
}
public class MainApp {
public static void main(String[] args) {
Person getinstance = Person.Getinstance();
Person getinstance1 = Person.Getinstance();
System.out.println(getinstance == getinstance1);//true
}
}
这种方式和上面一种一样,可能造成内存浪费
懒汉式(线程不安全)
class Person{
private static Person instance;
//私有化 构造 防止外部 new 对象
private Person(){
}
//对外提供静态方法 获取对象
public static Person Getinstance(){
if(instance == null){
instance = new Person();
}
return instance;
}
}
public class MainApp {
public static void main(String[] args) {
Person getinstance = Person.Getinstance();
Person getinstance1 = Person.Getinstance();
System.out.println(getinstance == getinstance1);//true
}
}
优缺点:线程不安全,不会浪费内存 如果在多线程下,一个线程进入if代码块 还未来得及往下执行,另一个线程 也通过了这个判断语句,这就会产生过个实例,所以多线程不可使用这个方式
懒汉式(线程安全,同步方法)
import java.io.File;
import java.io.IOException;
class Person{
private static Person instance;
//私有化 构造 防止外部 new 对象
private Person(){
}
//对外提供静态方法 获取对象 这样不会多个线程进入这个方法
public synchronized static Person Getinstance(){
if(instance == null){
instance = new Person();
}
return instance;
}
}
public class MainApp {
public static void main(String[] args) {
Person getinstance = Person.Getinstance();
Person getinstance1 = Person.Getinstance();
System.out.println(getinstance == getinstance1);//true
}
}
这种方法虽然解决看 多线程问题,但是效率太低了 每次获取实例对象都要进行同步
双重检查
public class Person{
private static volatile Person instance;
//私有化 构造 防止外部 new 对象
private Person(){
}
//对外提供静态方法
public static Person Getinstance(){
if (instance == null){
synchronized (Person.class){
if(instance == null){
instance = new Person();
}
}
}
return instance;
}
}
public class MainApp {
public static void main(String[] args) {
Person getinstance = Person.Getinstance();
Person getinstance1 = Person.Getinstance();
System.out.println(getinstance == getinstance1);//true
}
}
我们进行两次判断检查 这样可以保证线程安全,这样实例代码就执行了一次 后面访问时 判断 是否为空 直接return 实例化对象 也避免的反复进行方法同步 线程安全 延迟加载 效率较高
静态内部类
import java.io.File;
import java.io.IOException;
class Person{
private static volatile Person INSTANCE;
//私有化 构造 防止外部 new 对象
private Person(){
}
//静态内部类
private static class PersionInstance{
private static final Person INSTANCE = new Person();
}
public static Person Getinstance(){
return PersionInstance.INSTANCE;
}
}
public class MainApp {
public static void main(String[] args) {
Person getinstance = Person.Getinstance();
Person getinstance1 = Person.Getinstance();
System.out.println(getinstance == getinstance1);//true
}
}
这种方式 采用类装载的机制保证实例化只有一个线程 静态内部类被装载不会立刻实例化 而是在需要的时候 调用getinstace方法 才会装载静态内部类 而完成Person实例化 类的静态属性只会在第一次加载类的时候初始化 在这里jvm帮助我们保证线程的安全 在类的初始化 别的线程无法进入 避免线程的不安全 利用 静态内部类特点实现延迟加载 效率高
枚举方法实现单例
enum Person{
INSTANCE;//属性
public void sayok(){
System.out.println("ok");
}
}
public class MainApp {
public static void main(String[] args) {
Person instance1 = Person.INSTANCE;
Person instance2 = Person.INSTANCE;
System.out.println(instance1 == instance2);
}
}
避免多线程同步,防止反序列化
|