有以下特点: 1.该注解只能标记在“有且仅有一个抽象方法”的接口上。 2.JDK8接口中的静态方法和默认方法,都不算事抽象方法。 3.接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么也不算抽象方法。 4.该注解不是必须的,如果一个接口符合“函数式接口”定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。 @FunctionalInterface publicinterfaceFunctionalInterfaceTest{ Objec...

接口类: publicinterfaceHelloService{ StringsayHello(Stringname); } 实现类: publicclassHelloServiceImplimplementsHelloService{ @Override publicStringsayHello(Stringname){ return"你好,"+name; } } 客户端client: publicstaticvoidmain(String[]args){ HelloServicehelloService=newHelloServiceImpl(); HelloServicea...

  Olt1rl96HKat   2023年12月22日   20   0   0 动态代理动态代理

接口类: publicinterfaceHelloService{ StringsayHello(Stringname); } 实现类: publicclassHelloServiceImplimplementsHelloService{ @Override publicStringsayHello(Stringname){ return"你好,"+name; } } 代理工具类: importjava.lang.reflect.Proxy; / 动态代理工厂类,通过JDK动态代理创建代理对象 / publicclassProxyFactory{ publicstatic<T...

  Olt1rl96HKat   2023年12月22日   18   0   0 JavaJava动态代理动态代理

通过字节重组,重新生成对象来代替原始对象,以达到代理的目的。 字节码重组的基本步骤如下: 1.获取被代理对象的引用,利用反射获取到它的所有接口。 2.JDK动态代理类Proxy重新生成一个新的类,此类要实现刚才获取到的所有接口。 3.动态生成新类的Java代码。 4.编译.java文件成.class文件。 5.加载编译好的.class文件。 创建Person接口: publicinterfacePerson{ voidsing(); } 创建Customer类: publicclassCustomerimplementsPerson{ @Override publicvoidsing...

  Olt1rl96HKat   2023年12月19日   43   0   0 JDKjdk动态代理动态代理

Unsafe是CAS的核心类,由于Java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存的数据。 Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为Java中CAS操作的执行依赖于Unsafe类的方法。 注意Unsafe类中所有方法都是native修饰的,也就是说Unsafe类中的方法都直接调用操作系统底层资源执行相应任务。 变量valueOffset,表示该变量值子在内存中的偏移量,因为Unsafe就是根据内存偏移地址获取数据的。 变量value用volatile修饰,保证了...

  Olt1rl96HKat   2023年12月15日   20   0   0 unsafeJavaunsafeJava

CAS的全称为Compare-And-Swap,它是一条CPU并发原语。 它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。 CAS并发原语体现在Java语言中就是sun.misc.Unsafe类中的各个方法。调用Unsafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统勇于范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。

假设线程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也通过getIntVolatile(var1,var2)方法获取到value值3,此时刚好线程B没有被挂起并执行compareAndSwapInt方法比较内存值也是3,成功修改内存值为4,线程B...

  Olt1rl96HKat   2023年12月15日   41   0   0 AtomicIntegerAtomicInteger

CopyOnWrite容器即时复制的容器。往一个容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[]进行copy,复制出一个新的容器object[]newElements,然后新的容器object[]newElement里添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElement)。这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素,所以CopyOnWrite容器也是一种读写分离的思想,读和写是不同的容器。 publicbooleanadd(Ee){ finalReen...

自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处是减少线程上线文切换的消耗,缺点是循环会消耗CPU。 publicfinalintgetAndAddInt(Objectvar1,longvar2,intvar4){ intvar5; do{ var5=this.getIntVolatile(var1,var2); }while(!this.compareAndSwapInt(var1,var2,var5,var5+var4)); returnvar5; }

  Olt1rl96HKat   2023年12月15日   19   0   0 自旋锁自旋锁

AtomicReference是Java中的一个原子引用类型,位于java.util.concurrent.atomic包下。它提供了原子性地更新和访问引用对象的操作。 AtomicReference的主要特点如下: 1.原子性:AtomicReference提供了一些原子方法,可以在多线程环境下原子性地操作引用对象。 2.线程安全:由于AtomicReference的操作是原子性的,它可以确保在并发环境中正确处理引用对象的读取和更新,避免了竞态条件。 3.引用对象的原子性操作:AtomicReference的原子方法如get、set、compareAndSet等,针对引用对象进行操作,而不是...

  Olt1rl96HKat   2023年11月22日   21   0   0 AtomicReferenceAtomicReference

SnowFlake算法结构如下:大致分为了无效位、时间位、机器位和序列号位。 1.第一位:占用1bit,其值始终是0,没有实际作用(因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0)。 2.时间戳:占用41bit,精确到毫秒,总共可以容纳约69年的时间。 3.工作机器id:占用10bit,其中高位5bit是数据中心ID,低位5bit是工作节点ID,最多可以容纳1024个节点。 4.序列号:占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。 SnowFlake算法在同一个毫秒内最多可以生成的ID数量:...

  Olt1rl96HKat   2023年11月15日   26   0   0 时间戳SnowFlake时间戳snowflake

UidGenerator是Java实现的,提供了两种生成器:DefaultUidGenerator、CachedUidGenerator。 如对UID生成性能有要求,请使用CachedUidGenerator,支持缓存生成的id。 DefaultUidGenerator的原理是基于Snowflake算法,它使用了时间戳、机器ID和序列号来生成唯一的ID。其中, 时间戳用于保证ID的唯一性和有序性,机器ID用于区分不同的机器,序列号用于解决同一毫秒内并发生成ID的问题。单个实例的QPS能超过6000000。需要的环境:JDK8+,Mysql(用于分配WorkerId)。 优点:1.克服了雪花算法...

  Olt1rl96HKat   2023年11月15日   24   0   0 UidgeneratorUidgenerator

Tinyid是用Java开发的一款分布式id生成系统,基于数据库号段算法实现。 Tinyid提供了两种调用方式,一种基于Tinyid-server提供的http方式,另一种Tinyid-client客户端方式。 开源地址:https://github.com/didi/tinyid 实现原理 1.Tinyid是基于数据库发号算法实现的,简单来说是数据库中保存了可用的id号段,tinyid会将可用号段加载到内存中,之后生成id会直接内存中产生。 2.可用号段在第一次获取id时加载,如当前号段使用达到一定量时,会异步加载下一可用号段,保证内存中始终有可用号段。 3.(如可用号段1-1000被加载到...

  Olt1rl96HKat   2023年11月15日   32   0   0 TinyidTinyid

1、节点状态 需要引入3种节点状态:Follower(跟随者)、Candidate(候选者)、投票的触发点,Leader(主节点)。 2、进入投票状态的计时器 Follower、Candidate两个状态时,需要维护一个计时器,每次定时时间从150ms-300ms之间进行随机,即每个节点的每次的计时过期不一样,Follower状态时,计时器到点后,触发一轮投票。节点在收到投票请求、Leader的心跳请求并做出响应后需要重置定时器。 3、投票轮次Team Candidate状态的节点,每发起一轮投票,Term加一;Term的存储。 4、投票机制 每一轮一个节点只能为一个节点投赞成票,例如节点A中...

  Olt1rl96HKat   2023年11月15日   18   0   0 RaftRaft

1、格式化输出 StringdateStr="2023-11-0811:09:00"; Datedate=DateUtil.parse(dateStr); //format:2023/11/08 Stringformat=DateUtil.format(date,"yyyy/MM/dd"); System.out.println("format:"+format); //formatDate:2023-11-08 StringformatDate=DateUtil.formatDate(date); System.out.println("formatDate:"+formatDate)...

final关键字主要用在三个地方:变量、方法、类。 1.对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便绕不能再让其指向另一个对象。 2.当用final修饰一个类时,表明这个类不能被继承。final类中的所有变量方法都会被隐式地指定为final方法。 3.使用final方法的原因有两个,第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率,在早期的Javas实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用fina...

  Olt1rl96HKat   2023年11月05日   84   0   0 final关键字final关键字

为了能让HashMap存取高效,尽量减少碰撞,也就是要尽量把数据分配均匀。Hash值的范围值-2147483648到2147483647,前后加起来大概40亿的映射长度,只要哈希函数映射的比较均匀松散,一般应用是很难出现碰撞的。但问题是一个40亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数据的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。这个数组下标的计算方法是“(n-1)&hash”。(n代表数组长度)。这也就解释了HashMap的长度为什么是2的幂次方。 这个算法应该如何设计呢? 采用%取余的操作来实现。但是,重点来了,取余%...

  Olt1rl96HKat   2023年11月05日   38   0   0 取模运算hashmap取模运算hashmap

程序计数器主要有下面两个作用: 1.字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控,如:顺序执行、选择、循环、异常处理。 2.在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。 需要注意的时候,如果执行的是native方法,那么程序计数器记录的是undefined地址,只有执行的是Java代码时程序计数器记录的才是下一条指令的地址。所以,程序计数器私有主要是为了线程切换后恢复到正确的执行位置。

  Olt1rl96HKat   2023年11月05日   41   0   0 程序计数器程序计数器

多线程编程中一般线程的个数都大于CPU核心的个数,而一个CPU核心在任意时刻只能被一个线程使用,为了让这些线程都能得到有效执行,CPU采用的策略是为每个线程分配时间片轮询的形式。当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用,这个过程就属于一次上下文切换。 概括来说就是,当前任务在执行完CPU时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态。任务从保存到再加载的过程就是一次上下文切换。 上下文切换通常是计算密集型的,也就是说,它需要相当可观的处理器时间,在每秒几十上百次的切换中,每次切换都需要纳秒量级的时间。所以,上下文切换对...

ThreadPoolExecutor类中提供的构造方法。 / ⽤给定的初始参数创建⼀个新的ThreadPoolExecutor。 / publicThreadPoolExecutor(intcorePoolSize, intmaximumPoolSize,longkeepAliveTime,TimeUnitunit, BlockingQueue<Runnable>workQueue,ThreadFactorythreadFactory, RejectedExecutionHandlerhandler){ if(corePoolSize<0||maximumPoolSize&...

  Olt1rl96HKat   2023年11月05日   57   0   0 ThreadPoolExecutorThreadPoolExecutor
关注 更多

空空如也 ~ ~

粉丝 更多

空空如也 ~ ~