极客996

极客996

  • 23文章
  • 1评论
  • 3196文章浏览

简单谈谈对volatile理解

1.保障线程对主存中该数据的可见性 当修改了增加volatile 的变量时,会马上将变量值写回到主内存中,这时会在store 前对主内存的这个变量加锁,在store 通过总线的时候触发MESI缓存一致性协议,通过总线嗅探器将其他cpu工作内存中缓存该变量的行设置为无效。当cpu 完成变量的write 操作时,再对变量进行解锁。 2.不保证原子性 当线程A对工作内存中的i进行自增的时候,i+1 从主存中读取i i+1 写入主存 当执行第2的时候,变量i并未回到主存中,所以变量未加锁,这时线程B拿到i也进行自增,问题就在这,线程A中变量i的操作还未全部完成,线程B就已经拿到i了,这就违背了原子性的定义——要么成功,要么失败。所以为什么要使用 3.保证有序性 拿单例模式——懒汉式举例,为什么单例对象要加volatile class Singleton {
    //懒汉式
    private volatile static Singleton singleton;

    public static Singleton getInstance(String i) {

        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

} Object obj=new Object(); memory=allocate() //分配内存空间 obj(memory) //初始化对象 obj=memory //设置obj指向分配的内存地址,此时obj不为bull 一个理想中对象的实例化顺序是以上3步,但是编译器在优化的时候可能会打乱顺序,应该不会影响最终结果——实例化。 问题就在实例化的过程中,顺序打算为1-3-2,当另一个线程在执行到3也就是还未初始化对象的时候拿这个对象的实例进行操作就会出现问题。

Rick  52  2020-09-26 阅读全文

Java设计模式——装饰器模式

装饰者模式应该如何理解原理? 根据我的理解可以分为已下几个关注点: 1.被装饰的抽象对象—最终装饰成什么样的一个组合体 2.被装饰对象的实现—以该抽象实例为基础与其他装饰对象为一体 3.抽象装饰器—构造参数必须传入装饰对象,所有的装饰类基础该抽象装饰器 4.装饰器对象的实现—装饰对象为被装饰对象增强功能 /被装饰抽象对象:饮料
interface Drink {
    //价格
    public Integer price();

    //名称
    public String name();

    //描述
    public String desc();
}

//被装饰对象实现:咖啡
class Coffer implements Drink {
    private Integer price = 10;
    private String name = "普通咖啡";

    @Override
    public Integer price() {
        return price;
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public String desc() {
        return String.format("[%s] 价格:%d", name(), price());
    }


}

//抽象装饰器
abstract class Decoeator implements Drink {
    protected Drink drink;

    public Decoeator(Drink drink) {
        this.drink = drink;
    }

}

//牛奶装饰器
class MilkDecoeator extends Decoeator {
    private Integer price = 5;
    private String name = "牛奶";

    public MilkDecoeator(Drink drink) {
        super(drink);
    }

    @Override
    public Integer price() {
        return super.drink.price() + price;
    }

    @Override
    public String name() {
        return super.drink.name() + " + " + name;
    }

    @Override
    public String desc() {
        return String.format("[%s]  价格:%d", name(), price());
    }
}

class Sugar extends Decoeator {
    private Integer price = 1;
    private String name = "糖";

    public Sugar(Drink drink) {
        super(drink);
    }

    @Override
    public Integer price() {
        return super.drink.price() + price;
    }

    @Override
    public String name() {
        return super.drink.name() + " + " + name;
    }

    @Override
    public String desc() {
        return String.format("[%s]  价格:%d", name(), price());
    }
}

class Banana extends Decoeator {
    private Integer price = 3;
    private String name = "香蕉";

    public Banana(Drink drink) {
        super(drink);
    }

    @Override
    public Integer price() {
        return super.drink.price() + price;
    }

    @Override
    public String name() {
        return super.drink.name() + " + " + name;
    }

    @Override
    public String desc() {
        return String.format("[%s]  价格:%d", name(), price());
    }
} 测试:   public static void main(String[] args) {
        Drink drink = new Coffer();
        System.out.println(drink.desc());
        drink = new MilkDecoeator(drink);
        System.out.println(drink.desc());
        drink = new Sugar(drink);
        System.out.println(drink.desc());
        drink = new Banana(drink);
        System.out.println(drink.desc());
    } 难点:为什么 价格!=上个对象+装饰对象的价格 我们可以理解为最终装饰对象=被装饰对象+所有装饰对象的组合

Rick  71  2020-09-26 阅读全文

Java设计模式——静态代理模式

//静态代理设计实现
interface UserService {
    public void update();
}

class UserImpl implements UserService {
    @Override
    public void update() {
        System.out.println("修改用户..");
    }
}

class UserProxy implements UserService {
    UserService userService;

    public UserProxy(UserService userService) {
        this.userService = userService;
    }

    @Override
    public void update() {
        //操作之前拓展逻辑
        userService.update();
        //操作之后拓展逻辑
    }
}                                    运行: public static void main(String[] args) {                  
    UserProxy proxy = new UserProxy(new UserImpl());      
    proxy.update();                                       
}                                                         缺点:需要为每个代理类实现接口

Rick  56  2020-09-26 阅读全文

Java设计模式——单例模式

单例模式分为两种,饿汉式与懒汉式 1.饿汉式,随着类加载时被完成初始化,缺点是有可能浪费资源 class SingletonLazy {
    //懒汉式直接创建对象
    private static SingletonLazy singletonLazy = new SingletonLazy();

    private static SingletonLazy getInstance() {
        return singletonLazy;
    }
}

 2.懒汉式,懒汉式双重校验锁(线程安全) class SingletonHungry {
    //加volatile关键字是防止指令重排
    private static volatile  SingletonHungry singletonHungry;
    private static SingletonHungry getInstance() {
        //这一步是减少不必要的加锁损耗资源
        if (singletonHungry == null) {
            synchronized (SingletonHungry.class) {
                //这一步是第一个线程进来加锁进行对象的初始化
                if (singletonHungry == null) {
                    singletonHungry = new SingletonHungry();
                }
            }
        }
        return singletonHungry;
    }
}

Rick  82  2020-09-26 阅读全文

什么是双向链表?

看下Java中LinkedList的设计,通俗点说就是每个节点都包含了当前元素和上下两个节点信息。 private static class Node<E> {
        E item; 
        Node<E> next; 
        Node<E> prev; 

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

Rick  48  2020-09-26 阅读全文

String到底是在堆中还是在方法区中?

个人理解,不当之处请指正 String s="字符串"

String s1="字符串"

s==s1   //true 为什么s==s1? 使用""符号创建的字符串对象时jvm会在方法区的常量池中查找是否存在“字符串1”,没有就在方法区中的常量池中开辟一块空间存放字符串a并将引用s指向该地址,有的话则将引用直接指向该地址。 也可以总结出== 是判断两个变量是否指向同一个地方,即存储位置,也就是说是否引用同一个变量 String s="字符串1"

String s1 = new String("字符串2");

s == s1 //false
 为什么s == s1 为false 使用new 创建对象的实例在堆中,也就是说引用指向的是堆的地址。要注意的是括号里的"s",实际这里已经完成了上面所说的动作(在常量池中存放了一份),并在这之后又在堆中创建了一份。 String s="a"

String s1 = new String("s");

s == s1.intern() //true
 inter()方法的作用 inter()是一个本地方法,无法从源码中看出他的作用,所以查了一下资料,总结了一下jvm会从常量池中找到是否存在与该引用指向值相等的值,没有则在常量池中创建有则拿到该值引用地址返回。

Rick  146  2020-09-17 阅读全文