Java集合类时间复杂度分析
引言渐进时间复杂度的概念:若存在函数 f(n),使得当n趋近于无穷大时,T(n)/ f(n)的极限值为不等于零的常数,则称 f(n)是T(n)的同数量级函数。记作 T(n)= O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。渐进时间复杂度用大写O来表示,所以也被称为大O表示法。
时间复杂度推导原则:
如果运行时间是常数量级,用常数1表示。
只保留时间函数中的最高阶项。
如果最高阶项存在,则省去最高阶项前面的系数。
1、 List1.1、ArrayList
add(E e)方法直接在数组尾部插入,时间复杂度为O(1)
add(int index, E element)方法指定索引插入,会有数据的移动,时间复杂度为O(n)
get(int index)根据数组下标获取,时间复杂度O(1)
remove(int index)删除后,数据会存在移动,时间复杂度O(n)
1.2、LinkedList
add(E e) 尾插法,时间复杂度为O(1)
add(int index, E element)在指定位置插入,需要循环获取插入位置,时间复杂度 ...
JVM内存区域与垃圾回收
1、JAVA内存区域与内存溢出1.1、概述Java中JVM提供了内存管理机制,Java虚拟机在执行Java程序的过程中会把内存分为不同的数据区,如图:
1.2、程序计数器程序计数器是当前线程所执行的字节码的行号指示器,作用就是根据计数器的值获取下一条要执行的字节码指令。当执行的是java方法,则记录的是正在执行的虚拟机字节码指令的地址,如果是Native方法,则这个计数器的值为空。不存在任何OutOfMemoryError。
1.3、虚拟机栈每个普通Java方法(除去Native方法)在执行的时候都会同时创建栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息,每个方法被调用直到完成的过程对应着栈帧在JVM栈中的入栈与出栈。其中局部变量表所需要的内存空间在编译器间完成分配。
跟虚拟机栈相关联的异常有两种:
StackOverflowError
线程请求的栈深度大于虚拟机允许的最大深度。
OutOfMemoryError
虚拟机栈扩展时无法申请到足够的内存。
1.4、本地方法栈用于虚拟机执行Native方法,其他和本地方法栈相同。也会有StackOverflowError和 ...
阻塞队列之LinkedBlockingQueue分析
1、五种阻塞队列介绍
ArrayBlockingQueue有界队列,底层使用数组实现,并发控制使用ReentrantLock控制,不管是插入操作还是读取操作,都需要获取锁之后才能执行。
LinkedBlockingQueue底层基于单向链表实现,既可以当做有界队列,也可以当做无界队列使用。使用两个ReentrantLock实现并发控制:takelock和putlock。
SynchronousQueue底层使用单向链表实现,只有一个元素,同步的意思是一个写操作必须等到一个读操作之后才返回,指的是读写线程的同步。
PriorityBlockingQueue带排序的阻塞队列的实现,使用数组进行实现。并发控制使用ReentrantLock,队列为无界队列。有初始化参数指定队列大小,但是会自动扩容。使用最小堆来实现排序。
DelayedQueueDelayedQueue是使用PriorityBlockingQueue和Delayed实现的,内部定义了一个优先级队列,当调用offer的时候,把Delayed对象加入队列中,使用take先把first对象拿出来(peek),如果没有到达阈值,进行a ...
JAVA线程池原理与源码分析
1、线程池常用接口介绍1.1、Executor123public interface Executor {void execute(Runnable command);}
执行提交的Runnable任务。其中的execute方法在将来的某个时候执行给定的任务,该任务可以在新线程、池化线程或调用线程中执行,具体由Executor的实现者决定。
1.2、ExecutorServiceExecutorService继承自Executor,下面挑几个方法介绍:
1.2.1、shutdown()1void shutdown();
启动有序关闭线程池,在此过程中执行先前提交的任务,但不接受任何新任务。如果线程池已经关闭,调用此方法不会产生额外的效果。此方法不等待以前提交的任务完成执行,可以使用awaitTermination去实现。
1.2.2、shutdownNow()1List<Runnable> shutdownNow();
尝试停止所有正在积极执行的任务, 停止处理等待的任务,并返回等待执行的任务列表。 此方法不等待以前提交的任务完成执行,可以使用await ...
LeetCode|234.回文链表
题目描述
等级: 简单请判断一个链表是否为回文链表。
示例 1:
12输入: 1->2输出: false
示例 2:
12输入: 1->2->2->1输出: true
进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
思路对于单链表,回文,快慢指针,链表反转的考察。
“回文”是指正读反读都能读通的句子,它是古今中外都有的一种修辞方式和文字游戏,如“我为人人,人人为我”等。在数学中也有这样一类数字有这样的特征,成为回文数(palindrome number)。 [1] 设n是一任意自然数。若将n的各位数字反向排列所得自然数n1与n相等,则称n为一回文数。例如,若n=1234321,则称n为一回文数;但若n=1234567,则n不是回文数。 [1]
注意:
偶数个的数字也有回文数124421
小数没有回文数
链表反转请参考:反转单链表
通过两个快慢指针可以获取链表中的中间位置节点。(快慢指针步数相差一倍)
答案123456789101112131415161718192021222324252627282930 ...
RedisTemplate Failed to deserialize payload
问题123org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is java.io.EOFExceptionat org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:42)at org.springframework.data.red ...
分布式锁的实现分析
1、设计目标分布式部署的应用集群中保证数据更新的互斥性,且程序出现异常时,锁能够自动释放,避免死锁发生。
2、为什么要使用分布式锁为了保证分布式部署的应用集群中同一时间只有一个客户端对共享资源进行操作。根据锁的用途再细分:
对共享资源的操作是幂等性的,使用分布式锁能够避免重复操作,从而提高效率。
对共享资源的操作是非幂等的,比如订单状态的修改,如果多个客户端同时操作,最后的结果可能很遭,使用分布式锁可以让各个客户端分散时间操作。
3、分布式锁应具备哪些条件这也是分布式锁的关键技术。
互斥性这个是分布式锁的基本要求,分布式锁需要保证不同客户端的不同线程之间互斥。
可重入性支持锁的重入,减少资源消耗。
锁超时释放获取锁的客户端因为某些原因而宕机,而未能释放锁,其他客户端无法获取此锁,锁超时释放是为了避免死锁。
安全性锁只能被持有该锁的用户删除,而不能被其他用户删除。
高效与高可用加锁与解锁需要高效,并保证高可用,当部分节点宕机,客户端仍能获取锁或者释放锁。
支持阻塞与非阻塞阻塞就是线程获取不到锁一直阻塞,增加超时时间可以防止一直阻塞。非阻塞则获取不到锁不阻塞线程。
支持公平与非公平公 ...
分布式文件存储:FastDFS简单使用与原理分析
引言FastDFS属于分布式存储范畴,分布式文件系统FastDFS非常适合中小型项目,在我接手维护公司图片服务的时候开始接触到它,本篇文章目的是总结一下FastDFS的知识点。
用了2台2核4G的阿里云服务器做集群部署,具体部署步骤请参考:https://github.com/happyfish100/fastdfs/wiki
1、FastDFS分布式文件系统概述FastDFS是一个轻量级的开源分布式文件系统,作者为淘宝资深架构余庆。FastDFS主要解决了分布式文件存储与高并发访问的问题,实现了负载均衡,适合存储图片、视频、文档等文件,而且支持存储服务器的在线扩容。
2、FastDFS架构FastDFS服务端有两个角色:Tracker与Storage,其中Tracker主要做调度工作,有着负载均衡作用,Storage负责文件存取、同步等操作。
FastDFS系统结构:
2.1、Client客户端访问FastDFS分布式存储,一般为后端应用。
2.2、TrackerTracker在FastDFS集群中有两大作用:
管理Storage集群,在Storage服务启动时,会把自己注册到T ...
并发编程挑战:死锁与上下文切换
引言上下文切换(有时也称做进程切换或任务切换)是指 CPU 从一个进程或线程切换到另一个进程或线程。上下文切换会影响多线程执行速度。死锁是指多个进程或线程循环等待它方占有的资源而无限期地僵持下去的局面。
1、上下文切换上下文定义cpu发生进程或者线程切换时,所依赖的数据集合,比如一个函数有外部变量,函数运行时,必须获取外部变量,这些变量值的集合就是上下文。
引发问题对于CPU密集型任务,多线程处理会发生上下文切换,会影响到执行速度,如果时IO密集型,多线程技术优点尽显。
如何减少上下文切换
无锁并发编程,锁的获取与释放会发生上下文切换,多线程时会影响效率。无锁并发编程就是将数据分块,每个线程处理各自模块。比如LongAdder中部分代码。
CAS算法,并发编程时通过CAS算法更新数据,而不必加锁。如Java的atomic包下的工具类。
使用最少线程,减少不必要的线程创建,自定义线程池。
使用协程,在单线程中维护多任务调度,处理任务间切换,Golang对于协程的使用很强大。
2、死锁死锁定义死锁是进程死锁的简称,是由Dijkstra于1965年研究银行家算法时首先提出来的。系统发生死锁 ...
JAVA内存模型分析
在学习Java内存模型之前,先了解一下线程通信机制。
1、线程通信机制在并发编程中,线程之间相互交换信息就是线程通信。目前有两种机制:内存共享与消息传递。
1.1、共享内存Java采用的就是共享内存,本次学习的主要内容就是这个内存模型。内存共享方式必须通过锁或者CAS技术来获取或者修改共享的变量,看起来比较简单,但是锁的使用难度比较大,业务复杂的话还有可能发生死锁。
1.2、消息传递Actor模型即是一个异步的、非阻塞的消息传递机制。Akka是对于Java的Actor模型库,用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。消息传递方式就是显示的通过发送消息来进行线程间通信,对于大型复杂的系统,可能优势更足。
1.3、共享内存与消息传递的区别
2、内存模型Java既然使用内存共享,必然就涉及到内存模型。
2.1、结构抽象内存模型结构的抽象分为两个层次:
多核CPU与内存之间
Java多线程与主存之间
2.1.1、多核CPU与内存之间因为CPU的运行速度与内存之间的存取速度不成正比,所以,引入了多级缓存概念,相应的也引出了缓存读取不一致问题,当然缓存一致性协议解决了这个问题 ...