
JUC
文章平均质量分 88
jakiechaipush
小白进化中
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
并发编程中常见的设计模式
思考:在一个线程T1中如何正确安全的终止线程T2错误思路1使用线程对象的stop()方法停止线程,因为Stop方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁。错误思路2使用System.exit(int)方法停止线程,目的仅是停止一个线程,但这种做法会让整个程序都停止。Immutability模式,Copy-on-Write模式,Thread-Specific Storage模式本质上是为了避免共享。原创 2023-12-17 11:19:35 · 1442 阅读 · 0 评论 -
CompletableFuture原理解析
Future 是用于表示异步计算结果的接口。它提供了一种在计算完成时获取结果的机制,以及检查计算是否完成的方法。Callable 是一个代表有返回值任务的接口。与 Runnable 不同,Callable 的 call 方法可以返回一个值,并且可以抛出异常。//创建一个单一线程池 ExecutorService executorService = Executors . newSingleThreadExecutor();原创 2023-12-15 17:55:48 · 1648 阅读 · 0 评论 -
Fork和Join底层原理
思考: 线程池的线程数设置多少合适?我们调整线程池中的线程数量的最主要的目的是为了充分并合理地使用 CPU 和内存等资源,从而最大限度地提高程序的性能。在实际工作中,我们需要根据任务类型的不同选择对应的策略。传统线程池ThreadPoolExecutor有两个明显的缺点:一是无法对大任务进行拆分,对于某个任务只能由单线程执行;二是工作线程从队列中获取任务时存在竞争情况。这两个缺点都会影响任务的执行效率。为了解决传统线程池的缺陷,Java7中引入Fork/Join框架,并在Java8中得到广泛应用。原创 2023-12-14 10:36:44 · 1325 阅读 · 0 评论 -
阻塞队列底层原理分析(一)
它定义了队列的一些基本的操作规范,但这些方法都不会对队列进行阻塞E remove();E poll();E peek();ArrayBlockingQueue是最典型的有界阻塞队列,其内部是用数组存储元素的,初始化时需要指定容量大小,利用 ReentrantLock 实现线程安全。在生产者-消费者模型中使用时,如果生产速度和消费速度基本匹配的情况下,使用 ArrayBlockingQueue是个不错选择;当如果生产速度远远大于消费速度,则会导致队列填满, 大量生产线程被阻塞。原创 2023-12-12 09:30:47 · 1086 阅读 · 0 评论 -
ReetrantReadWriteLock底层原理
现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁(读多写少在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源(读读可以并发);但是如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写操作了(读写,写读,写写互斥)。在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量。针对这种场景,JAVA的并发包提供了读写锁ReentrantReadWriteLock,它内部,维护了 一对相关的锁,一个用于只读操作,称为读锁。原创 2023-12-11 09:26:10 · 1116 阅读 · 0 评论 -
深入理解CyclicBarrier
CyclicBarrier 作用是让一组线程相互等待,当达到一个共同点时,所有之前等待的线程再继续执行,且 CyclicBarrier 功能可重复使用。上面方法最核心的就是更新count,然后判断count是否为0,如果为0就开始执行唤醒逻辑(这里先不考虑),如果不为0就会进入trip这个条件队列进行阻塞,下面分析线程是如何进行条件队列阻塞的。发现里面实际逻辑调用的是dowait(false, 0L)方法。释放锁后回到await()方法,调用下面代码进行实际阻塞。下面分析头部出队的节点进入同步队列的逻辑。原创 2023-12-09 10:04:34 · 1159 阅读 · 0 评论 -
Semaphore和CountDownLatch详解
而调用await()方法时,当前线程就会判断state属性是否为0,如果为0,则继续往下执行,如果不为0,则使当前线程进入等待状态,直到某个线程将state属性置为0,其就会唤醒在 await()方法中等待的线程。Semaphore,俗称信号量,他是操作系统中PV操作原语在Java层面的实现,它也是基于AQS实现的。当幻想之后下一个线程就可以被唤醒执行后面的逻辑,假设被唤醒的线程可以获取到资源 ,它又会重新进入doAcquireSharedInterruptibly的for循环执行上面的获取资源的流程。原创 2023-12-07 11:26:33 · 1303 阅读 · 0 评论 -
synchronized底层原理(二)
从偏向锁的加锁解锁过程中可看出,当只有一个线程反复进入同步块时,偏向锁带来的性能开销基本可以忽略,但是当有其他线程尝试获得锁时,就需要等到safe point(安全点)时,再将偏向锁撤销为无锁状态或升级为轻量级,会消耗一定的性能,所以在多线程竞争频繁的情况下,偏向锁不仅不能提高性能,还会导致性能下降。:是指当有很多线程都尝试获取某个锁时,JVM会判断当前的锁是否适合做为偏向锁,如果不适合,就会取消偏向状态,将锁升级为轻量级锁或重量级锁。前面介绍了对象的几种加锁状态,分别是无锁、偏向锁、轻量级锁和重量级锁。原创 2023-12-05 10:54:40 · 906 阅读 · 0 评论 -
Java中实现单例模式的方式
这就实现了懒加载,即在需要的时候才创建单例对象,避免了在应用启动时就创建对象的开销。在Java中,使用标准的序列化和反序列化机制时,可能会破坏单例模式,因为反序列化会创建一个新的对象。为了避免这个问题,可以在单例类中添加一个特殊的方法,以便在反序列化时返回现有的单例对象。线程安全(Thread-Safe):由于静态内部类只会被加载一次,因此在加载过程中,其他线程无法访问静态内部类的加载过程。这就天然地保证了线程安全性。通过在静态代码块中进行对象的实例化,可以保证在类加载的时候只执行一次,从而实现单例模式。原创 2023-12-04 14:23:16 · 1072 阅读 · 0 评论 -
synchronized底层原理(一)
synchronized是JVM内置锁,基于Monitor机制实现,依赖底层操作系统的互斥原语Mutex(互斥量),它是一个重量级锁,性能较低。当然,JVM内置锁在1.5之后版本做了重大的 优化,如锁粗化(Lock Coarsening)、锁消除(Lock Elimination)、轻量级锁(Lightweight Locking)、偏向锁(Biased Locking)、自适应自旋(Adaptive Spinning)等技术来减少锁操 作的开销,内置锁的并发性能已经基本与Lock持平。原创 2023-12-04 11:12:06 · 972 阅读 · 0 评论 -
CAS原理详解
这就是所谓的ABA问题,具体来说,ABA问题指的是在多线程环境下,一个值从A变为B,然后再变回A,而在这个过程中,可能发生了其他操作,导致判断值是否相同的CAS操作出现误判。可以发现得到了正确的结果。但上面代码还是存在问题,上面创建了10个线程,但是同一时间只有一个线程在执行sum++,其它线程都在反复执行cas检查,不断的在for循环这里空转,空转占用cpu资源,这会对CPU资源造成很大的浪费(这里sum++影响不大,但对于一些复杂的逻辑空转会持续很久),因此我们就可以总结出CAS操作存在的一些缺陷。原创 2023-11-30 15:56:55 · 1010 阅读 · 0 评论 -
Java线程池底层原理
下面就来解释一下为什么上面不同的线程池执行速度会不同,对于newCachedThreadPool,它会根据需要创建很多线程,也会出现线程复用的情况所以它执行速度很快,然后newFixedThreadPool它只创建了10个线程去执行100个任务,速度会比newCachedThreadPool慢,最后是newSingleThreadExecutor它只有一个线程执行100个任务所以它是最慢的。这段代码描述了工作线程的主要执行逻辑,其中包括任务的获取、执行、异常处理、线程状态的检查以及线程的清理工作。原创 2023-11-28 10:23:51 · 1015 阅读 · 0 评论 -
深入理解JMM以及并发三大特性(2)
缓存锁定是指内存区域如果被缓存在处理器的缓存行中,并且在Lock操作期间被锁定,那 么当它执行锁操作回写到内存时,处理器不会在总线上声言LOCK#信号(总线锁定信号),而是修改内部的内存地址,并允许它的缓存一致性机制来保证操作的原子性,因为缓存一致性机制会阻止同时修改由两个以上处理器缓存的内存区域数据,当其他处理器回写已被锁定的缓存行的数据时,会使缓存行无效。在共享内存多处理器系统中,每个处理器都有一个单独的缓存内存,共享数据可能有多个副本:一个副本在主内存中,一个副本在请求它的每个处理器的本地缓存中。原创 2023-11-27 08:52:30 · 881 阅读 · 0 评论 -
深入理解JMM以及并发三大特性(1)
JMM实现共享变量的可见性的方式有两种,第一调用storeload方法加入内存屏障来实现可见性(针对x86架构),第二种方式就是上下文切换重新从共享内存加值恭喜变量的值(yield方法)原创 2023-11-23 10:09:39 · 180 阅读 · 0 评论 -
AQS原理
AQS时AbstractQueueSynchronizer,是阻塞式锁的同步器工具的框架。AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器。用State属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁getState:获取state状态setState:设置state状态compareAndSetState:CAS机制设置State状态。原创 2023-11-20 13:22:56 · 103 阅读 · 0 评论 -
java多线程中的Fork和Join
Fork/Join是JDK 1.7中加入的新的线程池的实现,它体现的使用分治的思想,适用于能够进行任务拆分的cpu密集型任务。所谓的任务拆分,是将一个大任务拆分为算法上相同的小任务,直到不能拆分可以直接求解。Fork/Join载分治的基础上加入了多线程,可以把每个任务的分解和合并交给不同的线程来完成,进一步提升了运算效率。Fork/Join默认会创建于cpu核心大小相同的线程池。原创 2023-11-20 12:08:15 · 327 阅读 · 0 评论 -
共享模型之不可变
分析:例如:一个线上商城应用,QPS达到数干,如果每次都重新创建和关闭数据库连接,性能会受到极大的影响。这时预先创建好一批连接,放入连接池。一次请求到达后,从连接池获取连接,使用完毕后再还回连接池,这样子既节约了连接的建立和关闭时间,也实现了连接的重用,不至于让庞大的连接数压垮数据库。i < 5;//1. 连接池大小//2. 连接对象数组//3. 连接状态数组//4. 构造方法i++) {//5. 从连接池中获取连接。原创 2023-11-14 13:41:07 · 101 阅读 · 0 评论 -
共享变量可见性问题以及解决方案
首先在了解可见性问题之前我们首先需要给出Java 内存模型的定义(JMM),java讲内存模型抽象为两个部分,主存以及工作内存,主 存也就是所有线程所共享的一段存储空间,工作内存是所有线程各种私有的一块内存空间,若此时某个线程想操作一个共享变量,它需要先将主存主的共享变量读取到自己的工作内存中,然后进行操作。此时就出现了一个问题,一个线程将对自己的更新推送至主存后,其它线程没有及时读取主存中共享变量的更新,而是一直使用自己工作内存中缓存的旧值,最后导致更新不可见,这就是所谓的可见性问题。@Slf4j。原创 2023-11-10 10:49:33 · 175 阅读 · 0 评论 -
ReentrantLock
可中断:synchronized获取了锁,除非线程自己结束,中途是不能取消锁的使用的可以设置超时时间:synchronized等待锁的线程在管程的Entry-List中等待,直到获取锁,但ReentrantLock可以设置超时时间,如果超过了等待时间,线程可以结束等待过程可以设置公平锁:公平锁可以防止饥饿可以支持多个条件变量:所以条件变量就是管程的wait-set,synchronized只有一个wait-set而ReentrantLock可以根据不同的等待条件设置多个wait-set。原创 2023-11-09 14:45:14 · 194 阅读 · 0 评论 -
线程活跃性
所谓线程的活跃性,我们知道每个线程所要执行的java代码是有限的,在执行一段时间后线程自然会陷入Terminated状态,但由于某些外部原因导致线程一直执行不完,一直处于活跃状态,这就是所谓的线程的活跃性。原创 2023-11-09 13:37:11 · 146 阅读 · 0 评论 -
Java线程状态转换
t线程用synchronized(obj)获取对象锁后,调用obj.wait(long n)方法,t线程从Runnable到timed_waiting状态。:当线程调用t.join(long n)方法时,当前线程从Runnable转移到Timed_waiting状态(注意是当前线程在t线程对象的管程上的等待),当前线程等待时间超过n毫秒,或t线程运行结束,或调用了当前线程的interrupt()时,当前线程从Time_waiting状态转移到Runnable状态。:初始状态,线程刚刚创建还未调用。原创 2023-11-09 12:39:58 · 127 阅读 · 0 评论 -
Park和UnPark底层原理
park和unpark也是一个线程暂停技术(让线程进入wait状态),与wait/notify不同的是,前者是LockSupport类中的方法,后者是Object类中的方法。其次,wait与notify和notifyall必须配合Object Monitor一起使用,而park和unpark不必一起使用。park和unpark是以线程为单位来阻塞和唤醒线程的,而notify只能随机唤醒一个等待线程。最后park和unpark可以先unpark,而wait和notify不行。原创 2023-11-08 14:50:10 · 427 阅读 · 0 评论 -
Wait-Notify机制
Owner线程发现条件不满足,调用wait方法,即可进入WaitSet变为WAITING状态BLOCKED和WAITING的线程都处于阻塞状态,不占用CPU时间BLOCKED线程会在Owner线程释放锁时唤醒WAITING线程会在Owner调用notify或notifyAll时唤醒,但唤醒后并不意味着立刻获得锁,仍需进入EntryList重新竞争while(条件B不成立)//代码逻辑。原创 2023-11-07 13:03:54 · 221 阅读 · 0 评论 -
synchronized优化原理
锁,轻量级锁,偏向锁,锁消除原创 2023-11-06 14:49:11 · 159 阅读 · 0 评论