佛山网站建设策划中,网站运营的具体工作包括哪些内容?

摘要:网站运营的具体工作包括哪些,佛山网站建设策划,做相亲网站赚钱吗,怎么做网页的欢迎页面线程安全的单例模式 饿汉模式懒汉模式单线程版多线程版多线程版(改进) 单例模式能保证某个类在程序中只存在 唯一 一份实例, 而不会创建出多个实例&a
网站运营的具体工作包括哪些,佛山网站建设策划,做相亲网站赚钱吗,怎么做网页的欢迎页面线程安全的单例模式 饿汉模式懒汉模式单线程版多线程版多线程版(改进) 单例模式能保证某个类在程序中只存在 唯一 一份实例, 而不会创建出多个实例#xff0c;从而节约了资源并实现数据共享。 比如 JDBC 中的 DataSource 实例就只需要一个. 单例模式具体的实现方式, 分成 “饿… 线程安全的单例模式 饿汉模式懒汉模式单线程版多线程版多线程版(改进) 单例模式能保证某个类在程序中只存在 唯一 一份实例, 而不会创建出多个实例从而节约了资源并实现数据共享。 比如 JDBC 中的 DataSource 实例就只需要一个. 单例模式具体的实现方式, 分成 “饿汉” 和 “懒汉” 两种. 饿汉模式 类加载的同时, 创建实例. class Singleton {private static Singleton instance new Singleton();// 私有化构造方法防止外部创建实例private Singleton() {}public static Singleton getInstance() {return instance;}}注意 使用 static 修饰 instance该实例就是该类的唯一实例。要私有化构造方法防止外部创建实例。饿汉模式中线程只读取了实例所以是线程安全的。 懒汉模式 单线程版 类加载的时候不创建实例. 只有真正第一次使用它的时候才创建实例. class Singleton {private static Singleton instance null;private Singleton() {}public static Singleton getInstance() {if (instance null) {instance new Singleton();}return instance;} }多线程版 上面的懒汉模式的实现是线程不安全的. 线程安全问题详解 因为这里面 读取 和 修改 instance 是两个操作不是原子操作线程安全问题发生在首次创建实例时. 如果在多个线程中同时调用 getInstance 方法, 就可能导致创建出多个实例. class Singleton {private static Singleton instance null;private Singleton() {}public synchronized static Singleton getInstance() {if (instance null) {instance new Singleton();}return instance;} }注意 针对 Singleton 类对象加锁类对象在一个程序中只能有一份保证所有线程调用 getInstance 方法时针对同一个对象进行加锁。 多线程版(改进) 代码可能出现线程安全问题的时机就在第一次创建实例时一旦实例已经创建好了, 后面再多线程环境调用 getInstance 就不再有线程安全问题了(不再修改 instance 了) 按照上面的加锁方式不管是否会发生线程安全问题都会加锁即使初始化之后线程安全了仍然存在大量锁竞争降低了程序的效率。 所以在加锁的基础上, 做出了进一步改动: 使用双重 if 判定, 降低锁竞争的频率 。给 instance 加上了 volatile 保证内存可见性以及防止指令重排序。 class Singleton {private static volatile Singleton instance null;private Singleton() {}public static Singleton getInstance() {if (instance null) {synchronized (Singleton.class) {if (instance null) {instance new Singleton();}}}return instance;} }为什么要双重 if 判定 加锁 / 解锁是一件开销比较高的事情. 而懒汉模式的线程不安全 只是发生在首次创建实例的时候. 因此后续使用的时候, 不必再进行加锁了. 外层的 if 就是判定下看当前是否已经把 instance 实例创建出来了如果已经创建出来了就不用再加锁了。 为什么要使用 volatile ? volatile 关键字详解 保证内存可见性内存可见性问题 多个线程调用 getInstance 方法就会造成大量读 instance 内存操作这样就可能导致编译器进行优化不读内存直接读寄存器一旦优化即使其他线程创建了实例该线程也感知不到。所以使用 volatile 关键字。 主要针对外外层的 if 判断因为 synchronized 也能防止指令重排序所以 内层判断不会受影响。 防止指令重排序 什么是指令重排序 举个栗子 一段代码是这样的 1. 去前台取下 U 盘 2. 去教室写 10 分钟作业 3. 去前台取下快递为了提高效率, JVM、CPU指令集会对其进行优化比如按 1-3-2的方式执行也是没问题可以少跑一次前台提高效率。这种就叫做指令重排序。 编译器对于指令重排序的前提是 “保持逻辑不发生变化”. 这一点在单线程环境下比较容易判断, 但是在多线程环境下就没那么容易了, 多线程的代码执行复杂程度更高, 编译器很难在编译阶段对代码的执行效果进行预测, 因此激进的重排序很容易导致优化后的逻辑和之前不等价. 其中创建实例 new Singleton() 又分为 三个步骤 分配内存空间对内存空间进行初始化把内存空间的地址赋给引用 instance 假如没有使用 volatile 关键字编译器可能对此进行了优化进行了指令重排序那么有可能优化为 1 - 3 - 2 。 这样的话当第一个线程 t1 要获取实例时因为实例为null, 所以肯定会创建实例但是可能编译器进行了优化那么可能顺序就变成了 1 - 3 - 2 先开辟了一块空间将空间地址赋值给引用对空间初始化 当进行完第二步把空间地址赋值给引用后还没来得及初始化此时另外一个线程 t2 来获取实例了 进行判断时发现 instance 不为空那么就直接返回实例了 t2 拿到实例后直接进行使用那么就会报错了因为虽然开辟了空间但是 t1 还没来得及对空间进行初始化拿到的是不完整的对象。 解决 对 instance 对象加上 volatile 关键字禁止指令重排序保证其他线程拿到的是一个完整的实例。 完整过程举栗 有三个线程, 开始执行 getInstance , 通过外层的 if (instance null) 知道了实例还没有创建的消息. 于是开始竞争同一把锁. 其中线程1 率先获取到锁, 此时线程1 通过里层的 if (instance null) 进一步确认实例还没有创建, 于是就把这个实例创建出来. 当线程1 释放锁之后, 线程2 和 线程3 也拿到锁, 也通过里层的 if (instance null) 来确认实例是否已经创建, 发现实例已经创建出来了, 就不再创建了. 后续的线程, 不必加锁, 直接就通过外层 if (instance null) 就知道实例已经创建了, 从而不再尝试获取锁了. 降低了开销. 总结 构造方法私有化防止外部创建实例。使用 static 修饰保证是该类的唯一实例。使用 volatile 修饰保证内存可见性以及防止指令重排序。双重 if 判断第一次判断是否需要加锁从而降低锁竞争提高效率。 第二层 if 判断是否真的需要创建实例。使用 synchronized 进行加锁防止第一次创建实例时由于线程安全问题而创建出多个实例。