有以下特点:1.该注解只能标记在“有且仅有一个抽象方法”的接口上。2.JDK8接口中的静态方法和默认方法,都不算事抽象方法。3.接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。4.该注解不是必须的,如果一个接口符合“函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了
接口类:public interface HelloService { String sayHello(String name); }实现类:public class HelloServiceImpl implements HelloService{ @Override public String sayHello(String name) { return
接口类:public interface HelloService { String sayHello(String name); }实现类:public class HelloServiceImpl implements HelloService{ @Override public String sayHello(String name) { retur
通过字节重组,重新生成对象来代替原始对象,以达到代理的目的。字节码重组的基本步骤如下:1.获取被代理对象的引用,利用反射获取到它的所有接口。2.JDK动态代理类Proxy重新生成一个新的类,此类要实现刚才获取到的所有接口。3.动态生成新类的Java代码。4.编译.java文件成.class文件。5.加载编译好的.class文件。创建Person接口:public interface Person
自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上线文切换的消耗,缺点是循环会消耗CPU。public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); }
CopyOnWrite容器即时复制的容器。往一个容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[]进行copy,复制出一个新的容器object[] newElements,然后新的容器object[] newElement里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElement)。这样做的好处是可以对CopyOnWrit
假设线程A和线程B两个线程同时执行getAndAddInt操作(分别跑在不同CPU上):1.AtomicInteger里面的value原始值为3,即主内存中AtomicInteger的value为3,根据JMM模型,线程A和线程B各自持有一份值为3的value的副本分别到各自的工作内存。2.线程A通过getIntVolatile(var1,var2)拿到value值3,这时线程A被挂起。3.线程B
CAS的全称为Compare-And-Swap,它是一条CPU并发原语。它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。CAS并发原语体现在Java语言中就是sun.misc.Unsafe类中的各个方法。调用Unsafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原
Unsafe是CAS的核心类,由于Java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存的数据。Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法。注意Unsafe类中所有方法都是native修饰的,也就是说Unsafe类中的方法
在 MySQL 中,我们可以使用 DATE_SUB 函数来进行时间减操作。下面是一个使用 DATE_SUB 函数将时间减去 30 分钟的示例:SELECT DATE_SUB(NOW(), INTERVAL 30 MINUTE);在上面的代码中,我们使用 NOW() 函数获取当前时间,然后用 INTERVAL 子句指定要减去的时间,这里是 30 分钟。查询结果将返回当前时间减去 30 分钟后的时间。
1、一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。因此,Java提供了一种用于停止线程的协商机制--中断,也即中断标识协商机制。中断只是一种协作协商机制,Java没有给中断增加任何语法,中断的过程完全需要程序员自己实现。它与stop最大的区别是:stop是由系统强制终止线程,而线程中断则给目标线程发送一个中断信号,如果目标线程没有接受线程中断的信号并结束线程,线程则不会终止
AtomicReference是Java中的一个原子引用类型,位于java.util.concurrent.atomic包下。它提供了原子性地更新和访问引用对象的操作。AtomicReference的主要特点如下:1.原子性:AtomicReference提供了一些原子方法,可以在多线程环境下原子性地操作引用对象。2.线程安全:由于AtomicReference的操作是原子性的,它可以确保在并发环
compareAndSwapLong方法是一个原子操作,通常用于并发编程中的无锁算法。它的作用是以原子比较方式比较并交换某个对象的一个long类型的字段。4个参数:1.Object obj:需要操作的对象。2.long offse:obj中要操作的字段的内存偏移量。3.long expected:预期的值,用于比较。4.long updated:要更新的值。compareAndSwapLong方法
1、节点状态需要引入3种节点状态:Follower(跟随者)、Candidate(候选者)、投票的触发点,Leader(主节点)。2、进入投票状态的计时器Follower、Candidate两个状态时,需要维护一个计时器,每次定时时间从150ms-300ms之间进行随机,即每个节点的每次的计时过期不一样,Follower状态时,计时器到点后,触发一轮投票。节点在收到投票请求、Leader的心跳请求
Tinyid是用Java开发的一款分布式id生成系统,基于数据库号段算法实现。Tinyid提供了两种调用方式,一种基于Tinyid-server提供的http方式,另一种Tinyid-client客户端方式。开源地址:https://github.com/didi/tinyid实现原理1.Tinyid是基于数据库发号算法实现的,简单来说是数据库中保存了可用的id号段,tinyid会将可用号段加载到
UidGenerator是Java实现的,提供了两种生成器: DefaultUidGenerator、CachedUidGenerator。如对UID生成性能有要求, 请使用CachedUidGenerator,支持缓存生成的id。 DefaultUidGenerator的原理是基于Snowflake算法,它使用了时间戳、机器ID和序列号来生成唯一的ID。其中,时间戳用于保证ID的唯一性和有序性,
SnowFlake 算法结构如下:大致分为了无效位、时间位、机器位和序列号位。1.第一位:占用1bit,其值始终是0,没有实际作用(因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0)。2.时间戳:占用41bit,精确到毫秒,总共可以容纳约69年的时间。3.工作机器id:占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,最多可
1、格式化输出String dateStr = "2023-11-08 11:09:00"; Date date = DateUtil.parse(dateStr); //format:2023/11/08 String format = DateUtil.format(date, "yyyy/MM/dd"); System.out.println("format:"+ format); //
Hystrix最基本的支持高可用的技术:资源隔离+限流。创建command; 执行这个command; 配置这个command对应的group和线程池。开始执行command,调用了这个command的execute()方法之后,Hystrix底层的执行流程和步骤以及原理是什么。步骤一:创建command一个HystrixCommand或HystrixObservableCommand对象,代表了
建立对象就是为了使用对象,Java程序通过栈上的reference数据来操作堆上的具体对象。对象的访问方式有虚拟机实现而定,目前主流的访问方式有1.使用句柄如果使用句柄的话,那么Java堆中奖会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。2.直接指针使用直接指针访问,那么Java堆对象的布局中就必须考虑如何放置访
运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(用于存放编译器生成的各种字面量和符号引用)。运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError异常。JDK1.7及之后版本的JVM已经将运行时常量池从方法区中移了出来,在Java堆(Heap)中开辟了一块区域存放运行时常量
ThreadPoolExecutor类中提供的构造方法。/** * ⽤给定的初始参数创建⼀个新的ThreadPoolExecutor。 */ public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable&g
多线程编程中一般线程的个数都大于CPU核心的个数,而一个CPU核心在任意时刻只能被一个线程使用,为了让这些线程都能得到有效执行,CPU采用的策略是为每个线程分配时间片轮询的形式。当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用,这个过程就属于一次上下文切换。概括来说就是,当前任务在执行完CPU时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任
程序计数器主要有下面两个作用:1.字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控,如:顺序执行、选择、循环、异常处理。2.在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。需要注意的时候,如果执行的是native方法,那么程序计数器记录的是undefined地址,只有执行的是Java代码时程序计数器记录的才是下一条
为了能让HashMap存取高效,尽量减少碰撞,也就是要尽量把数据分配均匀。Hash值的范围值-2147483648到2147483647,前后加起来大概40亿的映射长度,只要哈希函数映射的比较均匀松散,一般应用是很难出现碰撞的。但问题是一个40亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数据的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。这个
final关键字主要用在三个地方:变量、方法、类。1.对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便绕不能再让其指向另一个对象。2.当用final修饰一个类时,表明这个类不能被继承。final类中的所有变量方法都会被隐式地指定为final方法。3.使用final方法的原因有两个,第一个原因是把方法锁定,以防任何继承类
setnx(set if not exists),如果创建成功则表示获取到锁。setnx lock true 创建锁del lock 释放锁如果中途崩溃,无法释放锁?此时需要考虑到超时时间的问题。比如:expire lock 300由于命令是非原子的,所以还是会死锁如何解决?Redis支持set并设置超时时间的功能。比如:set lock true ex 30 nx。
1、Spring对bean进行实例化。2、Spring将值和bean的引用注入到bean对应的属性中。3、如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法。4、如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将bean所在的应用引用传入进来。5、如果bean实现了App
本质区别,主键是一种约束,唯一索引是一种索引。主键不能有空值(非空+唯一),唯一索引可以为空。主键可以是其他表的外键,唯一索引不可以。一个表只能有一个主键,唯一索引可以多个。都可以建立联合主键或联合唯一索引。主键->聚簇索引,唯一索引->非聚簇索引
-XX:+UseG1GC #开启使用G1垃圾收集器-XX:ParallelGCThreads #指定GC工作的线程数量-XX:G1HeapRegionSize #指定分区大小(1MB~32MB,且必须是2的N次幂),默认将整堆划分为2048个分区-XX:MaxGCPauseMillis #目标暂停(STW)时间(默认200ms)-XX:G1NewSizePercent #新生代内存初始空间(默认整
Copyright © 2005-2024 51CTO.COM 版权所有 京ICP证060544号