1.单例模式:
饿汉式 (可用) public class Demo{
private static Demo demo = new Demo();
private Demo(){
}
public static Demo getInstance(){
return demo;
}
}
懒汉式双锁(不可用) public class Demo{
private static Demo demo;
private Demo(){
}
public static Demo getInstance(){
if(demo==null){
synchronized(this)
if(demo==null){
demo = new Demo();
}
}
return demo;
}
}
bug:
缺陷:instance=new Singleton();
它不是一个原子操作,这句话做了3件事:
1.给Singleton的实例分配内存
2.初始化Sinhleton的构造器
3.将instance对象指向分配的内存空间(这时instance就非null了)
由于Java编译器允许处理器乱序执行,上面的顺序可能是1-2-3,也可能是1-3-2,这样就会出现问题。
原子操作:这种操作一旦开始,就一直运行到结束,中间不会切换到另一个线程
补充:在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作
volatile确保本条指令不会被编译器优化,且要求每次直接读值
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存,对volatile变量所有的写操作都能立刻被其他线程得知,保证此变量对所有线程的可见性,但是这并不代表基于volatile变量的运算在并发下是安全的,因为volatile只能保证内存可见性,却没有保证对变量操作的原子性。
3)如果是写操作,它会导致其他CPU中对应的缓存行无效。
volatile和synchronized:volatile标记的变量不会被编译器优化,一定程度上保证有序性,而synchronized标记的变量可以被编译器优化.
volatile比普通变量开销大,它需要插入内存屏障指令来保证处理器不会发生乱序执行,比synchronized开销小
推荐用:
public class Demo{
private static volatile Demo demo;
private Demo(){
}
public static Demo getInstance(){
if(demo==null){
synchronized(this)
if(demo==null){
demo = new Demo();
}
}
return demo;
}
}
Universal-Image-Loader和Eventbus就是通过此种方式来创建单例
静态内部类(推荐用)
public class Demo{
private Demo(){
}
private static class DemoInstance(){
private static final Demo demo = new Demo();
}
public static Demo getInstance(){
return DemoInstance.demo;
}
}
枚举(推荐用)
enum里面的枚举数据都是线程安全的,而enum实现的单例又是最简单的,Stackoverflow上最赞同的,也是Effective Java的作者推荐的方式
2.工厂模式
将具体创建产品实例的过程封装在工厂类中,实现客户端和创建产品实例的解耦,让客户端只负责消费,满足java设计原则的单一职责原则和面向对象的封装性(不用到处new实例)
简单工厂 :用来生产同一等级结构中的产品(不方便增加新产品,不修改代码无法扩展)。
工厂方法 :用来生产同一等级结构中的产品(支持增加新产品)。
抽象工厂:用来生产不同产品族的全部产品。(支持增加产品族)。
3.代理模式
1.虚拟代理,根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。(大图片的预览图)
2.安全代理,用来控制真实对象访问时的权限。(会员和游客)
3.智能指引,是指当调用真实对象时,代理处理另外一些事。(之前做什么,之后做什么)
动态代理:反射。AOP(代理对象不明确) Proxy类static Object newProxyInstance(ClassLoader loader,Class[ ] interfaces,InvocationHandler h):
loader:定义由哪个classloader对象来对生成的代理对象进行加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口这样我就能调用这组接口中的方法了
h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象的invoke方法上
public Object invoke(Object proxy,Method method,Object[ ]args) throws Throwable
{
System.out.println("before calling");
Object result=method.invoke(sub,args);
System.out.println("after calling");
return result;
}
AOP和OOP区别:
AOP面向切面,横向,从左到右;OOP面向对象,纵向,从上到下