high-level——单例模式和工厂模式(11)

一、单例模式

  • java设计模式分为三大类,创建型,结构型,行为型

  • 装饰器属于结构型

  • 单例模式属于创建型

  • 单例模式要求某个类的实例在整个应用中只能有一个,实例只能由本类来创建,实例在多线程情况下必须是线程安全的。

  • 在应用中,如果需要某个类的实例只能有一个,比如整个应用都要对同一 个文件进行读写,多个线程要操作同一个变量,多个线程要使用同一个连接对象来操作数据库。

  • spring 中的 Bean 默认都是单例的。

  • 单例可以节约资源,一是对象的创建只有一 次,节省内存,节省创建和销毁的时间。

  • 单例模式的设计原则,必须在类中具有三个要素:

    1. 需要一个静态的属于本类的成员变量。
    2. 构造方法必须是私有的,保证只能在内部创建对象。
    3. 需要一个静态的方法,创建对象并返回对象。保证在没有对象的前提下,可以创建唯一对象并返回对象。
  • 设计形式:

    1. 懒汉型,包括线程安全与非线程安全(加锁,用 synchronized 或可重入锁)只建议单线程情况下使用,不加锁。(使用时才创建)

      package com.zhong.test_6;
      
      public class Lazy {
               
          private static Lazy lazy;//懒汉型
          private Lazy() {
               }
          public static Lazy getInstance() {
               
              if (lazy == null)
                  lazy = new Lazy();
              return lazy;
          }
      }
      
    2. 饿汉型,是线程安全的。初始化时就创建对象。(可能存在浪费资源问题)

      package com.zhong.test_6;
      
      public class Hungry {
               
          private static Lazy lazy = new Lazy();//饿汉型
          private Lazy() {
               }
          public static Lazy getInstance() {
               
              return lazy;
          }
      }
      
    3. 双检锁型,主要用在多线程并发的情况下,并且效率很高。也不会出现资源浪费情况。多线程下最建议使用的。

      package com.zhong.test_6;
      
      public class DoubleCheckLock {
               
          private static DoubleCheckLock obj;
          private DoubleCheckLock() {
               }
          public static DoubleCheckLock getInstance() {
               
              if (obj == null) synchronized (DoubleCheckLock.class) {
               
                  if (obj == null) {
               
                      obj = new DoubleCheckLock();
                  }
              }
              return obj;
          }
      }
      
    4. 用枚举类型

    二、设计模式——工厂模式

    • 工厂是越来生产产品的,不同的工厂生产不同的产品。
    • java 中的工厂设计模式,是创建对象的最佳方式。它属于创建型模式。
    • 好处在于,可以隐藏创建对象的逻辑,对象的使用只需要告诉对方我要什么对象就可以了。
    • 工厂模式主要应用于对象的创建等比较繁琐的情形。
    • 使用工厂模式,必须返回接口类型。

    三、线程池

    • 现代的服务器都是多 cpu,线程采用多线程的方式来进行设计,可以更好的利用计算机的资源。如果不考虑多cpu多核的情况,单纯的多线程并不会提高程序的执行效率,相反还会降低效率。在多线程执行的情形下,需要创建线程,销毁线程,切换线程等,线程越多,栈区的内存消耗也越多,所以效率不会提高还会下降。
    1. 为什么还要使用线程池

      • 在多线程并发工作的前提下,如果需要的线程数据比较大,需要线程完成的任务比较多,势必就会产生大量的创建线程,销毁线程,切换线程的额外的工作,这会让系统的效率急剧下降,也容易造成内存泄露。线程池的出现,很好地解决了这个问题。线程池也是 jdk1.5 的新特性。在应用程序开始运行时,一次性创建一定数量的线程,把他们放在池中,如果有任务到达,不需要再去创建线程,直接从池中取出线程让它去执行当前的任务。任务执行完毕,线程仍会回到池中,可以重复使用。应用程序结束前,把线程池销毁。线程池可以极大的提高线程的复用率。
    2. 线程池的结构

      • 有人认为线程池是一个框架,是 jdk 提供的更好利用多线程来进行工作的一个基础框架。

      • 线程池基于一种特定的结构,利用它可以更好地对多线程进行有效的管理,并能够最大限度的节约资源,提升效率。

      • Interface Executor 线程池的基础接口,提供一个 execute() 方法来执行线程的任务。

      • public interface ExecutorService extends Executor

        • submit(Runnable task) 该方法执行线程执行目标(任务),底层调用了 execute()
        • shutdown() 关闭线程池
      • public abstract class AbstractExecutorService extends Object implements ExecutorService 实现了 submit方法

      • public class ThreadPoolExecutor extends AbstractExecutorService

        • 这是实现线程池功能最主要的类,该类的对象就是一个线程池。
        • 它有四个构造方法,构造方法的参数最多有七个,利用这些构造方法可以创建具有功能不同,特性不同的各自线程池。前三个构造方法都是调用第四个构造方法来创建线程池。
      • 线程池的几个主要要素:

        1. 池中线程的数量
        2. 空闲线程的生存时间,可以调整池的工作效率
        3. 任务队列,可分为有界和无界队列两种,有界表示队列中元素的数量是有限的,无界则没有限制。
        4. 线程工厂,线程包含两种,一种是没有返回值的线程(比如Runnable),另外一种有返回值且可以抛异常(Call)。
      • public class Executors extends Object

        • 提供了多种工厂方法,来创建不同特性种类的线程池。如果程序中需要创建线程池,也就是需要使用线程池,可以通过该类的工厂方法类得到线程池对象。该类就是工厂类。
      • 线程池的使用场景

        • 框架,web 应用服务器
        package com.zhong.test_9;
        
        import java.util.concurrent.ExecutorService;
        import java.util.concurrent.Executors;
        
        public class ThreadPoolDemo {
                   
            public static void main(String[] args) {
                   
                // ExecutorService pool1 = Executors.newFixedThreadPool(2);
                ExecutorService pool1 = Executors.newCachedThreadPool();
                pool1.submit((Runnable) () -> {
                   
                    while (true) {
                   
                        try {
                   
                            Thread.sleep(500);
                            System.out.println("一边吃饭");
                        } catch (InterruptedException e) {
                   
                            e.printStackTrace();
                        }
                    }
                });
        
                pool1.submit((Runnable) () -> {
                   
                    while (true) {
                   
                        try {
                   
                            Thread.sleep(500);
                            System.out.println("一边听歌");
                        } catch (InterruptedException e) {
                   
                            e.printStackTrace();
                        }
                    }
                });
        
                pool1.submit((Runnable) () -> {
                   
                    while (true) {
                   
                        try {
                   
                            Thread.sleep(500);
                            System.out.println("一边聊天");
                        } catch (InterruptedException e) {
                   
                            e.printStackTrace();
                        }
                    }
                });
        
                try {
                   
                    Thread.sleep(2000);
                    //  pool1.shutdownNow();//要求没有活动任务时才能关闭
                } catch (InterruptedException e) {
                   
                    e.printStackTrace();
                }
            }
        }
        

你可能感兴趣的:(java高级,java编程,java,编程语言)