浅谈Java Lambda表达式及其使用
什么是 Lambda表达式? 对于 Java 中的 lambda 表达式,我们可以把它简单的理解为一个函数。 比如,我们需要这样一个函数,它需要把两个数字相加,将结果返回 则可以这样定义 1int add(int a, int b); 但是我们知道,Java中函数是没有办法单独定义存在的,所以我们需要一个接口才能声明这个函数功能 123interface Function { int add(int a, int b);} 当我们需要实现这个方法的时候,一种方法就是定义一个新的类来实现这个接口 123456class Calc implements Function { @Override public int add(int a, int b) { return a + b; }} 除此之外,还有一种方法就是使用匿名类 123456Function addFunc = new Function() { @Override public int add(int...
Redis Rehash源码分析
接着之前说过的 Java HashMap的Rehash,这次我们来看看 Redis中的 hash结构(对应Java中的Map)是如何实现rehash的。 这次先说下结论,它的结构与HashMap基本一致,只是它有两个哈希表,平时只使用其中的第一个,在发生rehash时,会逐渐的将元素转移到另一个表中,全部转移完成后,再将引用赋值给第一个哈希表 下面我们来开始看代码 注:为了简化代码,只保留了源码中的主要字段,不是完整源码,需要的可以参看Redis源码 12345678910111213141516171819202122// 字典typedef struct dict { // 哈希表(一共有两个,这是rehash的关键) dictht ht[2]; long rehashidx; /* 没有在进行rehash时,rehashidx == -1 */} dict;// 哈希表// 每个字典都使用两个哈希表,从而实现渐进式 rehash(从一个哈希表渐进转到另一个哈希表)typedef struct dictht { dict...
漫谈 Java HashMap的Rehash
我们都知道Java中的HashMap是使用数组,结合链表来实现的,其结构如下: 如果加入的元素数量达到了设定的阈值,那么必然会涉及到扩容重新分配空间,将元素重新插入到新的空间中,也就是发生了rehash。这个过程其实是很耗时的,这也是为什么我们写代码时,最好指定的HashMap的初始空间大小的原因,就是为了避免或者减少发生rehash的次数。下面我们来看看这个过程的具体实现。 JDK是一直在升级的,其中的代码也在不断优化调整,我们这次主要就看下JDK1.7和 JDK1.8中的实现 JDK1.7 了解实现就免不了看源码,我们先来看下put方法的主要源码(为了方便阅读,省略了部分代码) 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849public V put(K key, V value) { int hash = hash(key.hashCode()); // 计算数组索引,插入 int i = indexFor(has...
Spring Bean 中 Bean解析创建过程(下)
这篇来跟踪一下AbstractBeanFactory#getBean(java.lang.String, java.lang.Class<T>)这个方法获取bean实例的流程,由于过程比较复杂,我们这里以一个简单的例子来跟进一下主要的流程 Spring 配置使用 下面我们看下具体的例子代码 spring配置文件 12345678910<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/bean...
Spring Bean 中 Bean解析创建过程(上)
spring-beans虽然是一个很基础的包,但是它已经包括了很多的功能,我们先看下如何在只使用spring-beans包的情况下,解析并拿到xml中配置的bean实例 spring-bean.xml 12345678<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class...
MyBatis(一)配置详解
MyBatis 基本用法 MyBatis是我们常用的ORM框架,先看一下它的基本用法(省略了Mapper相关的配置项): 123456789101112// 读取MyBatis配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");// 从配置文件中构建 SqlSessionFactory (全局只有一个,用于构建 SqlSession)SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);// 使用 SqlSessionFactory 创建 SqlSession(请求作用域,用后销毁)SqlSession session = sessionFactory.openSession(true);// 获取对应 MapperUserMapper mapper = session.getMapper(UserMapper.class);// 执行...
CountDownLatch应用及原理
CountDownLatch功能很简单,它主要有两个方法,await()与countDown(),初始创建的时候需要给它提供一个数值,调用countDown()方法会将数值减1,调用await()方法的时候会判断值是不是等于0,如果等于0就继续执行,否则就阻塞等待 123456// 初始化创建,值为1CountDownLatch countDownLatch = new CountDownLatch(1);// 如果countDownLatch中的值不是0则阻塞等待countDownLatch.await();// 将countDownLatch中的值进行减1countDownLatch.countDown(); 利用这两个方法,我们能用来做什么呢? 让一组线程等待同时开始 这种用法,我们只需要将CountDownLatch的初始值设为1,在需要线程阻塞的地方调用countDownLatch.await()方法,当满足开始条件后,调用countDownLatch.countDown()方法将类中的值减为0,让其他所有阻塞的线程可以几乎同时得到执行 123456789101112...
AbstractQueuedSynchronizer简述
工作流程 AbstractQueuedSynchronizer 是一个用于在竞争资源(如多线程)时使用的同步器,它内部使用了一个int类型的字段status表示需要同步的资源状态, 并基于一个先进先出(FIFO)的等待队列,队列中的每个节点表示要获取资源的线程 同步器主要是用于控制资源的获取以及释放,它可以用于独占模式和共享模式,这里我们以独占模式为例 在获取和释放资源时,我们需要实现自己的尝试获取和尝试释放的方法,利用status字段来控制成功与否 获取资源(独占模式) 1234567891011public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();}// 在独占模式下尝试获取资源(需要自己实现),成功返回true, 失败返回falseprotected boolean tryAcquire(int arg) &...
Redis数据结构概览
Redis支持的主要有5种数据类型,string, list, set, zset , hash,但是对于每种数据类型,Redis都不是简单的使用一种数据结构来实现,而是根据数据量等因素使用多种数据结构(SDS、双向链表、hashtable等),来达到提高效率、节省空间的目的,可以使用object encoding <key> 来查看数据的内部结构 (注:对于Redis的早期版本,list 结构内部是使用双向链表实现的)
Maven聚合与继承
maven聚合 聚合的目的是为了快速构建项目,当我们有几个maven模块,想要一次性构建,而不是到每个模块下面去执行maven命令,这时候就需要使用maven聚合(或者称为多模块)。 使用聚合的时候,我们需要新建一个maven项目,由它来控制构建其他的项目,其pom.xml配置与其他普通maven项目的区别主要在以下两个地方: 打包类型(packaging)必须为pom 需要在其中添加modules标签,在其中使用module标签包括需要同时构建的maven模块的名称路径,路径为相对于此pom.xml文件的路径(如果与pom.xml文件同级则直接写项目名,如果在上一级则写…/项目名)。 这样当我们在此项目下执行构建的时候,就会同时构建其中配置的项目。 下面举一个配置文件的例子: 12345678910<project ......> <groupId>XXX.XXX</groupId> <artifactId>XXX</artifactId> <version>1.0</version>...
