文章目录
1. 单例模式
不能new产生新的对象,只能获取一个对象。
分为懒汉式和饿汉式。
饿汉式: 不管是否需要创建对象,都会new一个对象出来。
懒汉式:等创建对象的时候,才会new,
单例模式实现步骤
1.私有化构造器(这样就不能new了)
2.构造一个共有方法 获得这个类的对象
饿汉单例模式:
/**
* @Description 恶汉模式
* @Author java川
* @Date 2021-04-28-12:39
*/
//缺点是浪费内存
public class Hungry {
private static final Hungry hungry=new Hungry ();//无论是否创建该Hungry对象 都生成一个对象
private Hungry()
{
} //私有化构造器 不能new
public static Hungry getInstance(){
return hungry;
}
}
懒汉单例模式(多线程不安全):
/**
* @Description
* @Author java川
* @Date 2021-04-28-13:31
*/
public class LazyManNoSafe {
private static LazyManNoSafe lazyManNoSafe = null;
//私有化构造器
private LazyManNoSafe() {
System.out.println (Thread.currentThread ().getName () + "OK");
}
//公开的获得实例化对象的方法
public static LazyManNoSafe getInstance() {
if (lazyManNoSafe == null) {
lazyManNoSafe = new LazyManNoSafe ();
}
return lazyManNoSafe;
}
public static void main(String[] args) {
//创建10个线程实例化对象
for (int i = 0; i < 10; i++) {
new Thread (){
@Override
public void run() {
LazyManNoSafe.getInstance ();
}
}.start ();
}
}
}
但是懒汉单例模式有一个问题是:
getInsance方法创建对象时,
lazyManNoSafe = new LazyManNoSafe (); 这一步操作new不是线程安全的,并且多线程环境调用getinstabce没有加锁,也导致线程不安全,会创建多个对象。
会创建多个对象(不一定是以下6个)
new分为三个步骤:
1.分配内存
2.执行构造方法实例化对象
3.对象地址指向内存地址。
如果线程A分配内存了,但是线程A跳过2步骤,直接对象地址指向内存地址,此时内存中是没有该对象的,线程B去调用getInance方法,就会直接返回该对象(但该对象线程A并没有初始化)。
所以我们需要保证线程安全,保证调用getInance方法的时候是一个线程在执行,同时使得new对象原子化。
多线程安全版DCL 懒汉式单例模式:
/**
* @Description 懒汉方式 缺点是只适合单线程 多线程的话就会创建多个
* @Author java川
* @Date 2021-04-28-12:44
*/
public class LazyMan {
private static volatile LazyMan lazyman=null;//volatitle保证原子性操作
//私有化构造器
private LazyMan(){
System.out.println (Thread.currentThread ().getName ()+"OK");
}
//公开的获得实例化对象的方法
public static LazyMan getInstance(){
if(lazyman==null){
synchronized (LazyMan.class){ //双重机制 加锁 防止多线程进来对象还未初始化 就进来了。
if(lazyman==null){
lazyman=new LazyMan ();//线程不安全
/*
1.分配内存空间
2.执行构造方法初始化对象
3.将对象地址指向内存空间地址。
*/
}
}
}
return lazyman;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread (new Runnable () {
public void run() {
LazyMan.getInstance ();
}
}).start ();
}
}
}
2.volatile关键字
volatile关键字保证了操作的原子性。
原子性:就是一个操作,不可分割。
volatile如何保证原子性的呢?
java的工作模式,多线程环境中每个线程都有一个独立的工作栈,还有一个主存,是公共区间。
每个线程从主存中读取共有变量,放到自己的工作栈中处理,但并不立刻写回主存,所以其他线程从主存中读取的数据并不是最新数据,就会导致线程不安全。
volatile关键字的作用就是将处理好的变量立刻写回主存,方便其他线程从主存中读取到最新数据。