java
文章平均质量分 87
java
永远别让世俗淹没生活的热情和浪漫
这个作者很懒,什么都没留下…
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
java使用freemarker导出复杂的excel表格
主要是两个map,一个map是封装模板的位置和生成表格的位置,第二个map是封装的数据。正常来说导出表格之后都是返回url请求的地址,这样在真实项目中根据地址就可以下载出来了。因为数据放到freemaker模板里面了所以只需要使用freemaker模板的语法取出数据存放在模板里面就可以了。都是先生成一个Excel表格的模板,最好是增加一行数据。具体看图里面的步骤。这个也不用多说,里面注释基本上已经解释清楚了,Excel导出打开出现问题的原因。原创 2024-07-14 08:30:07 · 1251 阅读 · 0 评论 -
优雅的参数校验
某些业务场景下,上面的注解未必可以提供很好的校验,validation也为我们提供了自定义注解参数校验。注解/*** 在注解没有显示申明,则min值默认是 0*//*** 在注解没有显示申明,则max值默认是18* @return*//*** 错误信息*//*** 分组*/Class原创 2024-07-14 08:29:56 · 526 阅读 · 0 评论 -
ConcurrentHashMap
Hashtable之所以效率低下主要是因为其实现使用了synchronized关键字对put等操作进行加锁,而synchronized关键字加锁是对整个对象进行加锁,也就是说在进行put等修改Hash表的操作时,锁住了整个Hash表,从而使得其表现的效率低下。原创 2024-07-14 08:29:30 · 983 阅读 · 0 评论 -
Semaphore
通过其限制执行的线程数量,达到限流的效果,每个线程执行之前,会先获取令牌。也是利用的了AQS机制来实现的,初始化的时候,将令牌数设置为statue.公平模式和非公平模式的区别的,公平模式会先判断是否队列中已经有阻塞的先层了,如果有则不获取令牌。非公平锁,就直接获取剩余令牌,并且减去自己需要的令牌在释放锁的时候,如果本来获取的令牌是3个,但是在释放的时候,释放四个,那么原先设置的令牌数也会增加。原创 2024-07-14 08:29:19 · 1029 阅读 · 0 评论 -
Phaser
在CountDownLatch中,主要是2个方法:await()和countDown(),在Phaser中,与之相对应的方法是awaitAdance(int n)和arrive()。原创 2024-07-14 08:29:07 · 993 阅读 · 0 评论 -
Exchanger
实现机制Exchanger的核心机制和Lock一样,也是CAS+park/unpark。比如有2条线程A和B,A线程交换数据时,发现slot为空,则将需要交换的数据放在slot中等待其它线程进来交换数据,等线程B进来,读取A设置的数据,然后设置线程B需要交换的数据,然后唤醒A线程,原理就是这么简单。但是当多个线程之间进行交换数据时就会出现问题,所以Exchanger加入了slot数组。Participant的作用是为每个线程保留唯一的一个Node节点, 它继承ThreadLocal,说明每个线程具有不原创 2024-07-14 08:28:50 · 864 阅读 · 0 评论 -
CyclicBarrier
回环删栏,其作用是让一组线程等待至某个状态的时候之后才可以通知执行。且当所有线程都释放之后,CyclicBarrier可以被重用。我们把这个状态就叫做barrier,当调用await()方法之后,线程就处于barrier了。这个类没有直接继承AQS,而是通过组合的方式来实现的,利用了ReentrantLock 和 Condition。创建CyclicBarrier的时候会设定一个count,仍在等待的数量。原创 2024-07-14 08:28:33 · 709 阅读 · 0 评论 -
CountDownLatch
是一个共享锁,是通过一个计数器实现的,只要等计数器的值变成0的时候,表示所有线程已经完成,然后就可以恢复线程继续执行。也是基于AQS实现的,当主线程调用await的时候,会判断state是否等于0,只有等于0的时候才能获取锁,因为CountDownLatch在初始化的时候,会设置一个计数器,所以此时这个线程会被挂起,使用的也是park方法。线程调用countDown的时候,会cas的将state-1保存起来。如果state-1之后等于0,则开始在共享模式下释放资源。原创 2024-07-14 08:28:22 · 1070 阅读 · 0 评论 -
ReentrantReadWriteLock
ReentrantReadWriteLock底层是基于AbstractQueuedSynchronizer来实现的,所以,ReentrantReadWriteLock的数据结构也依托于AQS的数据结构。只有读读不互斥,读写,写写,写读互斥。原创 2024-07-14 08:28:11 · 812 阅读 · 0 评论 -
可重入锁ReentrantLock
这也是和Nonfair最大的区别,Nonfair每一次都会尝试去获取资源,如果此时该资源恰好被释放,则会被当前线程获取,这就造成了不公平的现象,当获取不成功,再加入队列尾部。首先,t1线程的lock操作 -> t2线程的lock操作 -> t3线程的lock操作 -> t1线程的unlock操作 -> t2线程的unlock操作 -> t3线程的unlock操作。根据这个时序图来进一步分析源码的工作流程。如上图所示,最后,head的状态会变为0,t2线程会被unpark,即t2线程可以继续运行。原创 2024-07-14 08:27:45 · 960 阅读 · 0 评论 -
核心类AQS
*AbstractQueuedSynchronizer:**是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。当然,我们自己也能利用AQS非常轻松容易地构造出符合我们自己需求的同步器。原创 2024-07-14 08:27:34 · 655 阅读 · 0 评论 -
JUC原子类
是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值,其实现方式是基于硬件平台的汇编指令,就是说CAS是靠硬件实现的,JVM只是封装了汇编调用,那些AtomicInteger类便是使用了这些封装后的接口。CAS操作是原子性的,所以多线程并发使用CAS更新数据时,可以不使用锁。因为CAS需要在操作值的时候,检查值有没有发生变化,比如没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时则会发现它的值没有发生变化,但是实际上却变化了。原创 2024-07-14 08:27:21 · 812 阅读 · 0 评论 -
JAVA线程池
/ 核心线程数1,最大线程2,队列长度为3// 任务一 创建线程 执行executor.execute(new TaskThred("任务1"));// 任务二缓存到队列中 复用同一个线程executor.execute(new TaskThred("任务2"));// 任务三缓存到队列中 复用同一个线程executor.execute(new TaskThred("任务3"));// 任务四缓存到队列中 复用同一个线程。原创 2024-07-14 08:26:58 · 769 阅读 · 0 评论 -
线程的基本概念
无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。**运行中(Running):**进程正在执行线程的代码。等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。等待获取一个排它锁,如果其线程释放了锁就会结束此状态。线程准备运行,不一定立马就能开始执行。原创 2024-07-13 10:46:36 · 867 阅读 · 0 评论 -
多线程Join的理解
开发中使用多线程也非常少,之前因为有一个调取两个摄像头获取每帧进行活体检测时候,有人给了思路说到Join这个关键字,我才仔细的研究了一下这个。以前理解的意思是:使用join关键字,就是相当于调用join的线程如果没有执行完毕,其他线程都处于等待状态。这就相当是把线程串起来了一样。当在t2线程前面,main线程调用了t1线程的join,所以会让main线程暂时挂起。从而需要等到t1线程死亡之后才可以唤醒main线程继续执行下去。原创 2024-07-13 10:45:32 · 233 阅读 · 0 评论 -
JAVA 锁的分类
乐观锁和悲观锁对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。Java中,synchronized关键字和Lock的实现类都是悲观锁。而乐观锁认为自己在使用数据时不会有别的线程修改数据,所以不会添加锁,只是在更新数据的时候去判断之前有没有别的线程更新了这个数据。如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。乐观原创 2024-07-13 10:44:42 · 1148 阅读 · 0 评论 -
多线程通信
wait 是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了。这种方式使用起来并不是很好,代码编写复杂,而且线程 B 在被 A 唤醒之后由于没有获取锁还是不能立即执行,也就是说,A 在唤醒操作之后,并不释放锁。是一种非常灵活的实现线程间阻塞和唤醒的工具,使用它不用关注是等待线程先进行还是唤醒线程先运行,但是得知道线程的名字。的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放,调用。原创 2024-07-13 10:38:46 · 463 阅读 · 0 评论 -
Final关键字
一个既是static又是final 的字段只占据一段不能改变的存储空间,它必须在定义的时候进行赋值,否则编译器将不予通过,一旦被初始化之后便不会改变。修饰类的时候,该类不可以被继承,final类中所有的方法隐式为final。如果类被final修饰,但是想复用该类方法,并且想加上自己的方法,可以通过组合来实现,在自己的类中,将final修饰的类放进去。被声明为final但又没有给出定值的字段,但是必须在该字段被使用之前被赋值,这给予我们两种选择:在定义初赋值,或者在构造器进行赋值。原创 2024-07-13 10:37:55 · 936 阅读 · 0 评论 -
JAVA 内存模型
在 java 中,所有实例域、静态域和数组元素存储在堆内存中,堆内存在线程之间共享。局部变量,方法定义参数和异常处理器参数不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。Java 线程之间的通信由 Java 内存模型(本文简称为 JMM)控制,JMM 决定一个线程对共享变量的写入何时对另一个线程可见。原创 2024-07-13 10:37:17 · 895 阅读 · 0 评论 -
Volatile
缓存是分段(line)的,一个段对应一块存储空间,称之为缓存行,它是 CPU 缓存中可分配的最小存储单元,大小 32 字节、64 字节、128 字节不等,这与 CPU 架构有关,通常来说是 64 字节。为了保证各个处理器的缓存是一致的,实现了缓存一致性协议(MESI),每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。原创 2024-07-13 10:32:56 · 807 阅读 · 0 评论 -
synchronized
是利用锁的机制来实现同步的。**互斥性:**即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。**可见性:**必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。原创 2024-07-13 10:31:51 · 673 阅读 · 0 评论 -
并发编程基础
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。原创 2024-07-13 10:27:11 · 488 阅读 · 0 评论 -
JAVA GC
程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( “Stop The World” ),直到它收集结束。这个算法的基本思想就是通过一系列的称为”GC Roots“的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连的话,则证明此对象时不可用的。原创 2024-07-13 10:22:44 · 709 阅读 · 0 评论 -
java 常用算法
水仙花数指的是一个三位整数,它的各位数字的立方和等于这个数本身.。原创 2024-07-13 10:08:58 · 430 阅读 · 0 评论 -
常见的限流算法
计数器算法是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。那么我们可以这么做:在一开始的时候,我们可以设置一个计数器counter,每当一个请求过来的时候,counter就加1,,那么说明请求数过多;,具体算法的示意图如下:假设有一个恶意用户,他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,那么其实这个用户在 1秒里面,瞬间发送了200个请求。原创 2024-07-13 10:07:54 · 767 阅读 · 0 评论 -
JAVA IO模型
反之,原创 2024-07-13 10:06:31 · 850 阅读 · 0 评论 -
到底什么是对象,什么是对象的引用?对象和对象的引用有那些区别?
原文作者链接 https://blog.youkuaiyun.com/qq_26805137/article/details/52945688**3)左边的“Demo demo”创建了一个Demo类引用变量,它存放在栈空间中。也就是用来指向Demo对象的对象引用。2)末尾的()意味着,在对象创建后,立即调用Demo类的构造函数,对刚生成的对象进行初始化。1)右边的“new Demo”,是以Demo类为模板,在堆空间里创建一个Demo对象。4)“=”操作符使对象引用指向刚创建的那个Demo对象。转载 2024-07-13 10:03:56 · 158 阅读 · 0 评论
分享