传奇网站怎么制作教程栾川有做网站的吗

当前位置: 首页 > news >正文

传奇网站怎么制作教程,栾川有做网站的吗,网络营销论文范文,上海网络营销推广外包1 概述 本章的知识点非常重要。在单例模式与多线程技术相结合的过程中#xff0c;我们能发现很多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。本章的案例也充分说明#xff0c;线程与某些技术相结合中#xff0c;我们要考虑的事情会… 1 概述 本章的知识点非常重要。在单例模式与多线程技术相结合的过程中我们能发现很多以前从未考虑过的问题。这些不良的程序设计如果应用在商业项目中将会带来非常大的麻烦。本章的案例也充分说明线程与某些技术相结合中我们要考虑的事情会更多。在学习本章的过程中我们只需要考虑一件事情那就是如果使单例模式与多线程结合时是安全、正确的。 2 单例模式与多线程 在标准的23个设计模式中单例模式在应用中是比较常见的。但多数常规的该模式教学资料并没有结合多线程技术进行介绍这就造成在使用结合多线程的单例模式时会出现一些意外。 3 立即加载/饿汉模式 立即加载指的是使用类的时候已经将对象创建完毕。常见的实现办法就是new实例化也被称为“饿汉模式”。 public class MyObject {//立即加载方法 饿汉模式private static MyObject object new MyObject();private MyObject(){}public static MyObject getInstance(){return object;}} public class MyThread extends Thread{Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());} }public class Run1 {public static void main(String[] args) {MyThread t1 new MyThread();MyThread t2 new MyThread();MyThread t3 new MyThread();t1.start();t2.start();t3.start();} } 控制台打印的hashcode是同一个值说明对象是一个也就实现了立即加载型单例模式。此代码为立即加载模式缺点是不能有其他实例变量因为getInstance()方法没有同步所以有可能出现非线程安全问题。 4 延迟加载/懒汉模式 延迟加载就是调用get()方法时实例才被创建。常见的实现办法就是在get()方法中进行new实例化也被称为“懒汉模式”。 4.1 延迟加载解析 先看下面一段代码。 public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){if(object null){object new MyObject();}return object;} } public class MyThread extends Thread{Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());} } public class Run1 {public static void main(String[] args) {MyThread t1 new MyThread();MyThread t2 new MyThread();MyThread t3 new MyThread();t1.start();t2.start();t3.start();} } 4.2 延迟加载的缺点 前面两个实验虽然使用“立即加载”和“延迟加载”实现了单例模式但在多线程环境中“延迟加载”示例中的代码完全是错误的根本不能保持单例的状态。下面来看如何在多线程环境中结合错误的单例模式创建出多个实例的。  public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){try {if(object null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);object new MyObject();}}catch (InterruptedException e){e.printStackTrace();}return object;} } public class MyThread extends Thread{Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());} } public class Run1 {public static void main(String[] args) {MyThread t1 new MyThread();MyThread t2 new MyThread();MyThread t3 new MyThread();t1.start();t2.start();t3.start();} }控制台打印3个不同的hashCode说明创建了3个对象并不是单例的。这就是“错误的单例模式”如何解决呢 4.3 延迟加载的解决方案  1声明synchronzied关键字 既然多个线程可以同时进入getInstance()方法只需要对getInstance()方法声明synchronzied关键字即可。修改MyObject.java类。 public class MyObject {private static MyObject object;public MyObject() {}synchronized public static MyObject getInstance(){try {if(object null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);object new MyObject();}}catch (InterruptedException e){e.printStackTrace();}return object;} } 此方法在加入同步synchronzied关键字后得到相同实例的对象但运行效率很低。下一个线程想要取得 对象必须等待上一个线程释放完锁之后才可以执行。那换成同步代码块可以解决吗 2尝试同步代码块 修改MyObject.java类。 public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){try {synchronized (MyObject.class){if(object null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);object new MyObject();}}}catch (InterruptedException e){e.printStackTrace();}return object;} } 此方法加入同步synchronzied语句块后得到相同实例对象但运行效率也非常低和synchronzied同步方法一样是同步运行的。下面继续更改代码尝试解决这个问题。 3针对某个重要的代码进行单独的同步。 修改MyObject.java类。 public class MyObject {private static MyObject object;public MyObject() {}public static MyObject getInstance(){try {if(object null){//模拟在创建对象之前做一些准备工作Thread.sleep(3000);synchronized (MyObject.class) {object new MyObject();}}}catch (InterruptedException e){e.printStackTrace();}return object;} } 此方法使同步synchronzied语句块只对实例化对象的关键代码进行同步。从语句的结构上讲运行效率却是得到了提升但遇到多线程的情况还是无法得到同一个实例对象。 4使用DCL双检查锁机制 public class MyObject {private volatile static MyObject object;public MyObject() {}public static MyObject getInstance(){try {if(object null){Thread.sleep(2000);synchronized (MyObject.class){if(object null){object new MyObject();}}}}catch (InterruptedException e){e.printStackTrace();}return object;} } 使用volatile修改变量object使该变量在多个线程间可见另外禁止 object new MyObject()代码重排序。object new MyObject()包含3个步骤 1、memory allocate();//分配对象的内存空间 2、ctorInstance(memory);//初始化对象 3、object memory;//设置instance指向刚分配的内存地址 JIT编译器有可能将这三个步骤重新排序。 1、memory allocate();//分配对象的内存空间 2、object memory;//设置instance指向刚分配的内存地址 3、ctorInstance(memory);//初始化对象 这时构造方法虽然还没有执行但object对象已具有内存地址即值不是null。当访问object对象中的值时是当前声明数据类型的默认值。 创建线程类MyThread.java代码如下。 public class MyThread extends Thread{Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());} }public class Run1 {public static void main(String[] args) {MyThread t1 new MyThread();MyThread t2 new MyThread();MyThread t3 new MyThread();t1.start();t2.start();t3.start();} } 可见使用DCL双检查锁成功解决了懒汉模式下的多线程问题。DCL也是大多数多线程结合单例模式使用的解决方案。 5 使用静态内置类实现单例模式 DCL可以解决多线程单例模式的非线程安全问题。还可以使用其他办法达到同样的效果。 public class MyObject {private static class MyObjectHandler{private static MyObject object new MyObject();}public MyObject() {}public static MyObject getInstance(){return MyObjectHandler.object;} } public class MyThread extends Thread{Overridepublic void run(){System.out.println(MyObject.getInstance().hashCode());} }public class Run1 {public static void main(String[] args) {MyThread t1 new MyThread();MyThread t2 new MyThread();MyThread t3 new MyThread();t1.start();t2.start();t3.start();} }6 使用static代码块实现单例模式 静态代码块中的代码在使用类的时候就已经执行所以可以使用静态代码块的这个特性实现单例模式。 public class MyObject {private static MyObject object null;public MyObject() {}static {object new MyObject();}public static MyObject getInstance(){return object;} } public class MyThread extends Thread{Overridepublic void run(){for (int i 0; i 5; i) {System.out.println(MyObject.getInstance().hashCode());}} } public class Run1 {public static void main(String[] args) {MyThread t1 new MyThread();MyThread t2 new MyThread();MyThread t3 new MyThread();t1.start();t2.start();t3.start();} }