一、单例模式
-
java设计模式分为三大类,创建型,结构型,行为型
-
装饰器属于结构型
-
单例模式属于创建型
-
单例模式要求某个类的实例在整个应用中只能有一个,实例只能由本类来创建,实例在多线程情况下必须是线程安全的。
-
在应用中,如果需要某个类的实例只能有一个,比如整个应用都要对同一 个文件进行读写,多个线程要操作同一个变量,多个线程要使用同一个连接对象来操作数据库。
-
spring 中的 Bean 默认都是单例的。
-
单例可以节约资源,一是对象的创建只有一 次,节省内存,节省创建和销毁的时间。
-
单例模式的设计原则,必须在类中具有三个要素:
- 需要一个静态的属于本类的成员变量。
- 构造方法必须是私有的,保证只能在内部创建对象。
- 需要一个静态的方法,创建对象并返回对象。保证在没有对象的前提下,可以创建唯一对象并返回对象。
-
设计形式:
-
懒汉型,包括线程安全与非线程安全(加锁,用 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; } }
-
饿汉型,是线程安全的。初始化时就创建对象。(可能存在浪费资源问题)
package com.zhong.test_6; public class Hungry { private static Lazy lazy = new Lazy();//饿汉型 private Lazy() {} public static Lazy getInstance() { return lazy; } }
-
双检锁型,主要用在多线程并发的情况下,并且效率很高。也不会出现资源浪费情况。多线程下最建议使用的。
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; } }
-
用枚举类型
二、设计模式——工厂模式
- 工厂是越来生产产品的,不同的工厂生产不同的产品。
- java 中的工厂设计模式,是创建对象的最佳方式。它属于创建型模式。
- 好处在于,可以隐藏创建对象的逻辑,对象的使用只需要告诉对方我要什么对象就可以了。
- 工厂模式主要应用于对象的创建等比较繁琐的情形。
- 使用工厂模式,必须返回接口类型。
三、线程池
- 现代的服务器都是多 cpu,线程采用多线程的方式来进行设计,可以更好的利用计算机的资源。如果不考虑多cpu多核的情况,单纯的多线程并不会提高程序的执行效率,相反还会降低效率。在多线程执行的情形下,需要创建线程,销毁线程,切换线程等,线程越多,栈区的内存消耗也越多,所以效率不会提高还会下降。
-
为什么还要使用线程池
- 在多线程并发工作的前提下,如果需要的线程数据比较大,需要线程完成的任务比较多,势必就会产生大量的创建线程,销毁线程,切换线程的额外的工作,这会让系统的效率急剧下降,也容易造成内存泄露。线程池的出现,很好地解决了这个问题。线程池也是 jdk1.5 的新特性。在应用程序开始运行时,一次性创建一定数量的线程,把他们放在池中,如果有任务到达,不需要再去创建线程,直接从池中取出线程让它去执行当前的任务。任务执行完毕,线程仍会回到池中,可以重复使用。应用程序结束前,把线程池销毁。线程池可以极大的提高线程的复用率。
-
线程池的结构
-
有人认为线程池是一个框架,是 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
- 这是实现线程池功能最主要的类,该类的对象就是一个线程池。
- 它有四个构造方法,构造方法的参数最多有七个,利用这些构造方法可以创建具有功能不同,特性不同的各自线程池。前三个构造方法都是调用第四个构造方法来创建线程池。
-
线程池的几个主要要素:
- 池中线程的数量
- 空闲线程的生存时间,可以调整池的工作效率
- 任务队列,可分为有界和无界队列两种,有界表示队列中元素的数量是有限的,无界则没有限制。
- 线程工厂,线程包含两种,一种是没有返回值的线程(比如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(); } } }
-
-