我们在项目中使用缓存通常都是先检查缓存中是否存在,如果存在直接返回缓存内容,如果不存在就直接查询数据库然后再缓存查询结果返回。这个时候如果我们查询的某一个数据在缓存中一直不存在,就会造成每一次请求都查询DB,这样缓存就失去了意义,在流量大时,可能DB就挂掉了。
分布式锁一般有三种实现方式:
首先,为了确保分布式锁可用,我们至少要确保锁的实现同时满足以下四个条件:
java虚拟机运行时数据区
线程私有,可以看作是当前线程所执行的字节码的行号指示器。
线程私有,描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧StackFrame用于存储局部变量表等信息,程序计算器就是栈帧地址的指针。如果线程请求的栈深度大于虚拟机所允许的深度将抛出StackOverflowError异常;如果拓展时无法申请到足够的内存就会抛出OutOfMemoryError异常。
线程私有,为虚拟机使用到的native方法服务
线程共享,存放对象实例,细分还能分新生代和老生代,继续细分还能分eden,from survivor,to survivor
线程共享,存放已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。运行时常量池在次区。
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例 1:
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2:
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
它包含三个参数cas(v,e,n).v表示要更新的变量,e表示预期值,n表示下一个新值。仅当v==e时,才会将v的值设为n,如果v!=e,则说明其他线程做了更新,则当前线程说明都不做,执行下一次循环。最后cas返回当前v的真实值。如AtomicInteger的实现。
1.中断响应,如果一个线程中等待锁,接受通知可以中断,以防止无需等待,产生死锁。2.锁申请等待限时,除了等待外部通知外,也可以限时等待,超时让线程自动放弃。3.公平锁,synchronized进行控制的都是非公平锁,使用ReentrantLock可以使用公平锁/非公平锁。
允许多个线程同时访问,可以控制同时有几个线程能够访问
读写分离,读读不互斥,读写互斥,写写互斥
可以等待指定的如10个线程都完成任务,然后再do some thing
可以等等指定的如10个线程都准备就绪,然后再执行任务,再等待所有线程都执行完成,然后再do some thing
它可以在线程内任意位置让线程阻塞,和suspend()相比,它弥补了由于resume()在前发生,导致线程无法继续执行的情况。
Executor框架提供了各种类型的线程池,主要有以下工厂方法:
jdk1.7中Arrays.sort主要核心用的双轴快排,是一种改进的快排。先来复习一下大学里学习的普通快排算法。
单轴快排算法思想: