在文章《SpringCloudGateway源码解析(3)- 路由的装配》中,我们了解了网关路由的相关实现,这一章节,主要讲解下SpringCloudGateway中handler包实现,其中最核心的两个类FilteringWebHandler和RoutePredicateHandlerMapping。
在文章《SpringCloudGateway源码解析(3)- 路由的装配》中,我们了解了网关路由的相关实现,这一章节,主要讲解下SpringCloudGateway中handler包实现,其中最核心的两个类FilteringWebHandler和RoutePredicateHandlerMapping。
在文章《SpringCloudGateway源码解析-揭开SpringCloudGateway神秘面纱》中,我们从宏观上了解了Spring Cloud Gateway的整体架构和思想,本篇文章就是要带着大家了解网关的一等公民”路由”的前世和今生。
反应式编程,作为一种新的思想,以函数式编程为基础,受到越来越多的开发人员欢迎,Spring5作为行业的标准,也全面拥抱了Reactor框架。
1 | public class Test { |
单例模式分为了饿汉式和懒汉式,总体来说懒汉式要优于饿汉式,饿汉式不管是否其他线程调用了getInstance,都在类加载阶段创建了实例。而懒汉式则只有在调用的时候,才实例化对象,更加节省系统资源。
饿汉式:
1 | public class Singleton { |
懒汉式-双重检查
1 | /** |
懒汉式-内部类
1 | /** |
执行Main方法测试,从输出结果看,只有执行了SingletonLazy1.getInstance()方法,才开始加载内部类SingletonLazy1$InnerSingleton。
1 | public class Main { |
生产者-消费者模式在服务端编程中,是一种很常见的设计模式,比如消息队列的实现,就是这种思想。本文就是用Java语言编写一个简单的生产者消费者例子,从而引出concurrent包下的阻塞队列和ReentrantLock一些玩法。
##基础知识
首先复习下基础知识,在Java中concurrent包下并发队列分为阻塞队列和非阻塞队列,ConcurrentLinkedQueue是非阻塞队列,底层实现用了CAS。阻塞队列包括LinkedBlockingQueue,LinkedBlockingDeque,LinkedTransferQueue,ArrayBlockingQueue,阻塞队列底层是靠ReentrantLock实现。Condition包括await,signal,signalAll,Condition作为条件锁
我们知道Lock的本质是AQS,AQS自己维护的队列是当前等待资源的队列,AQS会在被释放后,依次唤醒队列中从前到后的所有节点,使他们对应的线程恢复执行,直到队列为空。
而Condition自己也维护了一个队列,该队列的作用是维护一个等待signal信号的队列。
但是,两个队列的作用不同的,事实上,每个线程也仅仅会同时存在以上两个队列中的一个,流程是这样的:
1、线程1调用reentrantLock.lock时,尝试获取锁。如果成功,则返回,从AQS的队列中移除线程;否则阻塞,保持在AQS的等待队列中。
2、线程1调用await方法被调用时,对应操作是被加入到Condition的等待队列中,等待signal信号;同时释放锁。
所以,发送signal信号只是将Condition队列中的线程加到AQS的等待队列中。只有到发送signal信号的线程调用reentrantLock.unlock()释放锁后,这些线程才会被唤醒。可以看到,整个协作过程是靠结点在AQS的等待队列和Condition的等待队列中来回移动实现的,Condition作为一个条件类,很好的自己维护了一个等待信号的队列,并在适时的时候将结点加入到AQS的等待队列中来实现的唤醒操作。 signal就是唤醒Condition队列中的第一个非CANCELLED节点线程,而signalAll就是唤醒所有非CANCELLED节点线程,本质是将节点从Condition队列中取出来一个还是所有节点放到AQS的等待队列。尽管所有Node可能都被唤醒,但是要知道的是仍然只有一个线程能够拿到锁,其它没有拿到锁的线程仍然需要自旋等待,就上上面提到的第4步(acquireQueued)。
##生产者-消费者代码
1 | /** |
1 | /** |
1 | static void test0() { |
1 | /** |