1.啥么是设计模式答设计模式是计算机大佬们研究出来的一些定式为了是小菜鸡们代码下限也能够有所保证大佬们就研究出一些“设计模式”解决一些固定场景问题的固定套路。2.单例模式单例模式单例单个实例对象。虽然一个类语法的角度来说可以无限创建实例但是在实际场景中可能有时候就只希望这个类只有唯一的一个实例。Java代码中如何实现单例模式呢1.饿汉模式2.懒汉模式3.饿汉模式class Singleton{ private static Singleton instancenew Singleton();//创建一个实例 private Singleton(){} public static Singleton getInstace(){ return instance; } } public class Demo15 { //饿汉模式 //在类加载时就创建一个实例当需要使用时直接返回实例 //缺点在类加载时就创建一个实例如果不需要使用就会浪费内存 //优点在类加载时就创建一个实例当需要使用时直接返回实例不会创建多个实例 public static void main(String[] args) { Singleton s1Singleton.getInstace(); Singleton s2Singleton.getInstace(); System.out.println(s1s2);//true } }注意饿汉模式的不能够新建实例是通过private Singleton(){}来保证的这段代码是线程安全的。4.懒汉模式class Singleton{ private Singleton(){} private static Singleton instancenull; public static Singleton getInstance(){ if(instancenull){ instancenew Singleton(); } return instance; } }这段代码有线程不安全的问题。具体有两类一类是要解决线程的原子性一类是要解决指令重排序。class Singleton{ private Singleton(){} private static Object locknew Object(); private static volatile Singleton instancenull; public static Singleton getInstance(){ if(instancenull){ synchronized(lock){ if(instancenull){ instancenew Singleton(); } // return instance; } } return instance; } } public class Demo18 { //懒汉模式 //在需要使用时才创建一个实例当需要使用时直接返回实例 //缺点在需要使用时才创建一个实例如果不需要使用就会浪费内存 //优点在需要使用时才创建一个实例当需要使用时直接返回实例不会创建多个实例 public static void main(String[] args) { Singleton singleton1Singleton.getInstance(); Singleton singleton2Singleton.getInstance(); System.out.println(singleton1singleton2); } }原子性是通过synchronized来解决的,指令重排序是通过volatile来解决的。外层的if就是判定下看当前是否已经把instance实例创建出来了。同时为了避免内存可⻅性导致读取的instance出现偏差,于是补充上volatile。当多线程⾸次调⽤getInstance,⼤家可能都发现instance为null,于是⼜继续往下执⾏来竞争锁,其中竞争成功的线程,再完成创建实例的操作。当这个实例创建完了之后,其他竞争到锁的线程就被⾥层if挡住了。也就不会继续创建其他实例。下面拿一个比较通俗易懂的例子解释一下。比如有很多滑稽老铁看到一个美女校花在房间中并且单身。1. 有三个线程,开始执⾏getInstance ,通过外层的if (instance null) 知道了实例 还没有创建的消息.于是开始竞争同⼀把锁.2. 其中线程1率先获取到锁,此时线程1通过⾥层的if (instance null) 进⼀步确认实例 是否已经创建.如果没创建,就把这个实例创建出来。3. 当线程1释放锁之后,线程2和线程3拿到锁,也通过⾥层的if (instance null) 来 确认实例是否已经创建,发现实例已经创建出来了,就不再创建了.4. 后续的线程,不必加锁,直接就通过外层if (instance null) 就知道实例已经创建了, 从⽽不再尝试获取锁了.降低了开销.5.阻塞队列阻塞队列是啥么阻塞队列是一种特殊的队列也遵守“先进先出”的原则。阻塞队列是一中线程安全的数据结构并且有以下的特性当队列满的时候继续入队的队列就会阻塞直到有其他线程从队列中取走元素。当队列空的时候继续出队的队列会被阻塞直到有其他线程往队列中插入元素在JAVA标准库中有一个现成的实现BlockingQueue,BlockingQueue提供的offer和take带有阻塞功能。实现一个阻塞队列class myBlockingQueue{ private static Object locknew Object(); private static int size0; private static int head0; private static int tail0; private static String[] queuenull; public myBlockingQueue(int capacity){ queuenew String[capacity]; } public static void offer(String str) throws InterruptedException{ synchronized(lock){ if(sizequeue.length){ lock.wait(); } queue[tail]str; tail; size; if(tailqueue.length){ tail0; } lock.notify(); } } public static String take(){ synchronized(lock){ if(size0){ try { lock.wait(); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } String resqueue[head]; head; size--; if(headqueue.length){ head0; } lock.notify(); return res; } } }阻塞队列常用于生产者与消费者模型当中。6.生产者与消费者模型生产者消费者模式就是通过一个容器来解决生产者与消费者之间的强耦合关系的。生产者和消费者彼此之间不之间通讯而是通过阻塞队列来进行通讯的所以生产者生产完数据之后不需要之间给消费者而是将生产者生产的数据放入到阻塞队列中由消费者把数据从阻塞队列中取走。1.阻塞队列相当于一个缓冲区平衡了生产者和消费者的处理能力。比如在秒杀场景下服务器同一时刻可能会收到大量的支付请求如果直接处理这些支付请求服务器可能扛不住(每个支付请求的处理都需要比较复杂的流程)。这个时候就可以把这些请求都放到一个阻塞对列中然后再有消费者线程慢慢的来处理每个支付请求。这样做可以有效进行削峰,防止服务器被突然来到的一波请求直接冲垮。2.阻塞队列也能使生产者和消费者之间解耦比如过年一家人一起包饺子。一般都有明确分工比如一个人负责擀饺子皮其他人负责包饺子。擀饺子皮的人就是生产者包饺子的人就是消费者。3.可以减少资源竞争提高效率。缺点一.系统更复杂 二.引入队列的层数太多就会增加网络开销用阻塞队列实现一下生产者和消费者模型。1用JAVA标准库的BlockingQueue来实现public static void main(String[] args) { BlockingQueueString queuenew LinkedBlockingQueue(66); Thread prcoudenew Thread(()-{ int count0; while(true){ try { queue.offer(count); System.out.println(生产者生产了count); count; Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo19.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); Thread consumernew Thread(()-{ while(true){ String res; try { res queue.take(); System.out.println(消费者消费了res); Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo19.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); prcoude.start(); consumer.start(); try { prcoude.join(); consumer.join(); } catch (InterruptedException ex) { System.getLogger(Demo19.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } }2.用实现好的阻塞队列实现生产者消费者public static void main(String[] args) { myBlockingQueue queuenew myBlockingQueue(66); Thread prcoudenew Thread(()-{ int count0; while(true){ try { queue.offer(count); System.out.println(生产者生产了count); count; Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); Thread consumernew Thread(()-{ int count0; while(true){ try { String itemqueue.take(); System.out.println(消费者消费了item); count; Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); prcoude.start(); consumer.start(); try { prcoude.join(); consumer.join(); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } }
单例模式与生产者消费者模式的实现与应用
发布时间:2026/6/30 11:38:14
1.啥么是设计模式答设计模式是计算机大佬们研究出来的一些定式为了是小菜鸡们代码下限也能够有所保证大佬们就研究出一些“设计模式”解决一些固定场景问题的固定套路。2.单例模式单例模式单例单个实例对象。虽然一个类语法的角度来说可以无限创建实例但是在实际场景中可能有时候就只希望这个类只有唯一的一个实例。Java代码中如何实现单例模式呢1.饿汉模式2.懒汉模式3.饿汉模式class Singleton{ private static Singleton instancenew Singleton();//创建一个实例 private Singleton(){} public static Singleton getInstace(){ return instance; } } public class Demo15 { //饿汉模式 //在类加载时就创建一个实例当需要使用时直接返回实例 //缺点在类加载时就创建一个实例如果不需要使用就会浪费内存 //优点在类加载时就创建一个实例当需要使用时直接返回实例不会创建多个实例 public static void main(String[] args) { Singleton s1Singleton.getInstace(); Singleton s2Singleton.getInstace(); System.out.println(s1s2);//true } }注意饿汉模式的不能够新建实例是通过private Singleton(){}来保证的这段代码是线程安全的。4.懒汉模式class Singleton{ private Singleton(){} private static Singleton instancenull; public static Singleton getInstance(){ if(instancenull){ instancenew Singleton(); } return instance; } }这段代码有线程不安全的问题。具体有两类一类是要解决线程的原子性一类是要解决指令重排序。class Singleton{ private Singleton(){} private static Object locknew Object(); private static volatile Singleton instancenull; public static Singleton getInstance(){ if(instancenull){ synchronized(lock){ if(instancenull){ instancenew Singleton(); } // return instance; } } return instance; } } public class Demo18 { //懒汉模式 //在需要使用时才创建一个实例当需要使用时直接返回实例 //缺点在需要使用时才创建一个实例如果不需要使用就会浪费内存 //优点在需要使用时才创建一个实例当需要使用时直接返回实例不会创建多个实例 public static void main(String[] args) { Singleton singleton1Singleton.getInstance(); Singleton singleton2Singleton.getInstance(); System.out.println(singleton1singleton2); } }原子性是通过synchronized来解决的,指令重排序是通过volatile来解决的。外层的if就是判定下看当前是否已经把instance实例创建出来了。同时为了避免内存可⻅性导致读取的instance出现偏差,于是补充上volatile。当多线程⾸次调⽤getInstance,⼤家可能都发现instance为null,于是⼜继续往下执⾏来竞争锁,其中竞争成功的线程,再完成创建实例的操作。当这个实例创建完了之后,其他竞争到锁的线程就被⾥层if挡住了。也就不会继续创建其他实例。下面拿一个比较通俗易懂的例子解释一下。比如有很多滑稽老铁看到一个美女校花在房间中并且单身。1. 有三个线程,开始执⾏getInstance ,通过外层的if (instance null) 知道了实例 还没有创建的消息.于是开始竞争同⼀把锁.2. 其中线程1率先获取到锁,此时线程1通过⾥层的if (instance null) 进⼀步确认实例 是否已经创建.如果没创建,就把这个实例创建出来。3. 当线程1释放锁之后,线程2和线程3拿到锁,也通过⾥层的if (instance null) 来 确认实例是否已经创建,发现实例已经创建出来了,就不再创建了.4. 后续的线程,不必加锁,直接就通过外层if (instance null) 就知道实例已经创建了, 从⽽不再尝试获取锁了.降低了开销.5.阻塞队列阻塞队列是啥么阻塞队列是一种特殊的队列也遵守“先进先出”的原则。阻塞队列是一中线程安全的数据结构并且有以下的特性当队列满的时候继续入队的队列就会阻塞直到有其他线程从队列中取走元素。当队列空的时候继续出队的队列会被阻塞直到有其他线程往队列中插入元素在JAVA标准库中有一个现成的实现BlockingQueue,BlockingQueue提供的offer和take带有阻塞功能。实现一个阻塞队列class myBlockingQueue{ private static Object locknew Object(); private static int size0; private static int head0; private static int tail0; private static String[] queuenull; public myBlockingQueue(int capacity){ queuenew String[capacity]; } public static void offer(String str) throws InterruptedException{ synchronized(lock){ if(sizequeue.length){ lock.wait(); } queue[tail]str; tail; size; if(tailqueue.length){ tail0; } lock.notify(); } } public static String take(){ synchronized(lock){ if(size0){ try { lock.wait(); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } String resqueue[head]; head; size--; if(headqueue.length){ head0; } lock.notify(); return res; } } }阻塞队列常用于生产者与消费者模型当中。6.生产者与消费者模型生产者消费者模式就是通过一个容器来解决生产者与消费者之间的强耦合关系的。生产者和消费者彼此之间不之间通讯而是通过阻塞队列来进行通讯的所以生产者生产完数据之后不需要之间给消费者而是将生产者生产的数据放入到阻塞队列中由消费者把数据从阻塞队列中取走。1.阻塞队列相当于一个缓冲区平衡了生产者和消费者的处理能力。比如在秒杀场景下服务器同一时刻可能会收到大量的支付请求如果直接处理这些支付请求服务器可能扛不住(每个支付请求的处理都需要比较复杂的流程)。这个时候就可以把这些请求都放到一个阻塞对列中然后再有消费者线程慢慢的来处理每个支付请求。这样做可以有效进行削峰,防止服务器被突然来到的一波请求直接冲垮。2.阻塞队列也能使生产者和消费者之间解耦比如过年一家人一起包饺子。一般都有明确分工比如一个人负责擀饺子皮其他人负责包饺子。擀饺子皮的人就是生产者包饺子的人就是消费者。3.可以减少资源竞争提高效率。缺点一.系统更复杂 二.引入队列的层数太多就会增加网络开销用阻塞队列实现一下生产者和消费者模型。1用JAVA标准库的BlockingQueue来实现public static void main(String[] args) { BlockingQueueString queuenew LinkedBlockingQueue(66); Thread prcoudenew Thread(()-{ int count0; while(true){ try { queue.offer(count); System.out.println(生产者生产了count); count; Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo19.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); Thread consumernew Thread(()-{ while(true){ String res; try { res queue.take(); System.out.println(消费者消费了res); Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo19.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); prcoude.start(); consumer.start(); try { prcoude.join(); consumer.join(); } catch (InterruptedException ex) { System.getLogger(Demo19.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } }2.用实现好的阻塞队列实现生产者消费者public static void main(String[] args) { myBlockingQueue queuenew myBlockingQueue(66); Thread prcoudenew Thread(()-{ int count0; while(true){ try { queue.offer(count); System.out.println(生产者生产了count); count; Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); Thread consumernew Thread(()-{ int count0; while(true){ try { String itemqueue.take(); System.out.println(消费者消费了item); count; Thread.sleep(1000); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } } }); prcoude.start(); consumer.start(); try { prcoude.join(); consumer.join(); } catch (InterruptedException ex) { System.getLogger(Demo33.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); } }