Collection集合
1、Java 为什么要有集合?首先,java 是一门面向对象语言,操作对象是我们的日常。既然操作就需要有东西把对象存储起来。于是容器就应运而生,初学者接触到的第一个容器就是数组,但这远远不够,根据不同的对象以及不同的业务,我们需要用到不同的容器。比如,不想要重复对象,我们就会想到用 set 容器,想要对象有序我们会用 List 。不管是 List、Set。他们都会有共性, 而 java 就根据这些共性,给我们提供了 Collection 集合。
2、Collection接口框架图
由上面的 Collection 接口框架图,我们可以知道 Collection 是 List、Set、Queue 的父接口,看到这里,你们可能会问,Map 哪去了?其实,Java 中的容器,包括 Collection 和 Map ,Map 是另外一个体系。
3、Collection的方法
Collection 接口定义了以上待实现的方法。比如:
size() 计算容器长度
isEmpty() 是否为空
contains() 是否包含某个对象
containsAll() 是否包含另一个集合的所有对象
...
Lambda表达式(三)
1、如何使用 lambda表达式1.1 构造器引用public class ConstructMethodExample { public static void main(String [] args) { // 构造方法方法引用--无参数(可以使用方法引用) Supplier<Method> supplier = Method::new; System.out.println(supplier.get()); // 等价于 Supplier<Method> supplier2 = () -> new Method(); System.out.println(supplier2.get()); // 构造方法方法引用--有参数 Function<String, Method> uf = name -> new Method(name); Method method = uf.apply ...
Lambda表达式(二)
1、如何使用 lambda表达式1.1 lambda语法// 格式遵循: (接口参数)->表达式(具体实现的方法)(paramters) -> expression 或 (parameters) ->{ expressions; }
具体解释,如上图。此外,lambda 语法注意点:
可选类型声明:方法参数不需要声明参数类型,编译器可以统一识别参数值。
可选的参数圆括号:一个参数无需定义圆括号,但无参数或多个参数需要定义圆括号。
可选的大括号:如果具体实现方法只有一个语句,就不需要使用中括号{}。
可选的返回关键字:如果具体实现方法只有一个表达式,则编译器会自动返回值,如果有多个表达式则,中括号需要指定明表达式返回了一个数值。
具体使用示例:
public class Example { // 定义函数式接口,只能有一个抽象接口,否则会报错 // 希望在编译期检出报错,请加 @FunctionalInterface 注解 public interface Hello { String h ...
Redis数据结构-SDS
1、Redis设计SDS的背景
优化C语言char* 字符数组的不足
操作效率低:获取长度需遍历,O(N)复杂度
二进制不安全:无法存储包含 \0 的数据(char* 数组用’\0’ 表述字符串结束 )
2、SDS数据结构SDS 结构中记录了字符数组 使用的长度和分配的空间大小,避免了对字符串的遍历操作,可以直接获取到字符串的长度len,降低了操作开销 (空间换时间)
struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* 字符数组现有长度(uint8_t 是8位无符号整形,占用1字节)*/ uint8_t alloc; /* 字符数组的已分配空间,不包括结构体和0结束字符*/ unsigned char flags; /* SDS类型*/ char buf[]; /*字符数组*/};
flags表示SDS的类型,一共有5种类型 sdshdr5(已废弃)、sdshdr8、sdshdr16、sdshdr32、sdshdr64, 区别:不同类型SDS ...
Lambda表达式(一)
1、什么是lambda表达式Java8 是我们使用最广泛的稳定 Java 版本,lambda 就是其中最引人瞩目的新特性。lambda 是一种闭包,它允许把函数当做参数来使用,是面向函数式编程的思想,可以使代码看起来更加简洁。是不是听得一脸懵逼?我举个栗子你就明白了。
烂掉牙的例子,在没有 lambda 时候,我们是这样写的:
// 内部类写法public class InnerClassMain { public static void main(String[] args) { //匿名内部类写法 new Thread(new Runnable() { @Override public void run() { System.out.println("内部类写法"); } }).start(); }}
有 lambda 之后,我们就用 ...
JUC(七)
1、锁1.1、公平锁与非公平锁
公平fair锁:遵守FIFS,先来先服务,按照线程的申请顺序
非公平Nofair:多个线程获取锁的顺序不是严格按照申请的顺序,存在插队现象,在高并发的环境下,可能造成优先级反转或者饥饿现象,synchronized是一种非公平锁
public ReentrantLock() { // 默认非公平锁 sync = new NonfairSync();}
公平锁的先来先服务,保证公平,同样也是致命的问题。比如买咖啡时,你买一杯,你前面那位买99杯,你的体验会特别的糟糕,现实中,你可以与前面的人商量让店员先给你做,然而公平锁是不允许这样交换的,就是先来先得。
1.2、可重入锁(递归锁)指的是同一线程外层函数获得锁之后,内层递归函数仍然能够获取该锁的代码同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。也就是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块同步方法1内部调用同步方法2,当线程获取同步方法1的锁,它也会获取方法2的锁。Synchronized和ReentrantLock是典型的可重入锁,可重入锁 ...
JUC(六)
1、CPU密集型任务该任务需要大量的运算,没有阻塞,CPU一直全速运行。CPU密集任务只有在多核CPU上才可能通过多线程得到加速。CPU密集型任务配置尽可能少的线程数量,线程池大小的一般公式:CPU核数+1个线程
比如像加解密,压缩、计算等一系列需要大量耗费 CPU 资源的任务,大部分场景下都是纯 CPU 计算
对于 CPU 密集型计算,多线程本质上是提升多核 CPU 的利用率,所以对于一个 8 核的 CPU,每个核一个线程,理论上创建 8 个线程就可以了。
如果设置过多的线程数,实际上并不会起到很好的效果。此时假设我们设置的线程数量是 CPU 核心数的 2 倍,因为计算任务非常重,会占用大量的 CPU 资源,所以这时 CPU 的每个核心工作基本都是满负荷的,
而我们又设置了过多的线程,每个线程都想去利用 CPU 资源来执行自己的任务,这就会造成不必要的上下文切换,此时线程数的增多并没有让性能提升,反而由于线程数量过多会导致性能下降。
因此,对于 CPU 密集型的计算场景,理论上线程的数量 = CPU 核数就是最合适的,不过通常把线程的数量设置为CPU 核数 +1,会实现最优的利用率。 ...
JUC(五)
1、线程池的工作原理我们在工作中或多或少都使用过线程池。但是为什么要使用线程池呢?从它的名称中我们就可以猜到,线程池是使用了一种池化技术(Pooling Technology)。和很多其他池化技术一样,都是为了更高效的利用资源,例如连接池,内存池等。
数据库连接是一种很昂贵的资源,创建和销毁都需要付出高昂的代价。为了避免频繁地创建数据库连接,所以产生了数据库连接池技术。优先在池子中创建一批数据库连接,当有需要访问数据库时,直接到池子中去获取一个可用的连接,使用完了之后再归还到连接池中去。
同样的,线程也是一种很宝贵的资源,并且也是一种有限的资源,创建和销毁线程也同样需要付出不菲的代价。我们所有的代码执行都是由一个一个的线程支撑起来的,如今的芯片架构也决定了我们必须编写多线程执行的程序,以获得最高的程序性能。那么怎样高效地管理多线程之间的分工与协作就成了一个关键问题,Doug Lea大神为我们设计并实现了一款线程池工具,通过该工具就可以实现多线程的能力,并实现任务的高效执行与调度。为了正确合理地使用线程池工具,我们有必要对线程池的原理进行了解。
了解线程池工作原理主要有三个方面:线程池状 ...
JUC(四)
在学习面向对象OOP时,肯定听过一句话,java皆对象,要什么对象就new什么对象。之后学习spring时,发现通过DI依赖注入后,便不再手动new对象了。同理,在之前javase学习Thread时,手动new Thread,麻烦,另外gc也需要去不断收回,耗性能。那么,我们能不能将所需要的线程提前创建好,并且可以反复利用呢?线程池来了
1、简介线程池的工作主要是控制运行线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等待,等待其他线程执行完毕。
优势-主要特点是:线程复用;控制最大并发数;管理线程
降低资源消耗:通过复用已创建的线程降低线程的创建和销毁造成的消耗
提高响应速度:任务到达时,任务可以不需要等待线程创建,即可立即执行
提高线程的可管理性:线程是稀缺资源,如果无限制创建,会消耗系统资源,降低系统稳定性,使用线程池可以进行统一分配管理,调优和监控
2、线程池创建
线程池种类
说明
Executors.newCachedThreadPool()
一池多线程带缓存,执行很多短期异步的小程序或者负载 ...
JUC(三)
1、阻塞队列
BlockingQueue接口实现类
说明
ArrayBlockingQueue
基于数组结构的有界阻塞队列,此队列按FIFO原则对元素进行排序
LinkedBlockingQueue
底层链表,有界(默认Integer.MAX_VALUE)吞吐量通常高于ArrayBlockingQueue
SynchronousQueue
一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
PriorityBlockingQueue
支持优先级排序的无界阻塞队列
DelayQueue
使用优先级队列实现的延迟无界阻塞队列
LinkedTransferQueue
由链表实现的无界阻塞队列
LinkedBlockingDeque
由链表实现的双向阻塞队列
2、阻塞队列的好处在多线程领域,所谓阻塞,在某些情况下会挂起线程(即阻塞),一旦条件满足会被自动唤醒。为什么需要BlockingQueue?好处是我们不需要关心什么时候需要阻塞线程,是什么时候需要唤醒线程,因为这一切BlockingQueue都包办了。在 ...