1.juc?线a线߳?Դ??
2.七天杀上GitHub榜首!Java并发编程深度解析实战,程源程源JUC底层原理揭秘
3.juc是码j码治疗什么的
4.Java并发指南14:JUC中常用的Unsafe和Locksupport
5.JUC之CountDownLatch与CyclicBarrier
6.八股文JUC知识总结
juc?߳?Դ??
一:简述如果我们想要生成一个随机数,通常会使用Random类。线a线但是程源程源在并发情况下Random生成随机数的性能并不是很理想,今天给大家介绍一下JUC包中的码j码数据库查询网站源码用于生成随机数的类--ThreadLocalRandom.(本文基于JDK1.8)
二:Random的性能差在哪里
Random随机数生成是和种子seed有关,而为了保证线程安全性,线a线Random通过CAS机制来保证线程安全性。程源程源从next()方法中我们可以发现seed是码j码通过自旋锁和CAS来进行修改值的。如果在高并发的线a线场景下,那么可能会导致CAS不断失败,程源程源从而导致不断自旋,码j码这样就可能会导致服务器CPU过高。线a线
protected?程源程源int?next(int?bits)?{ long?oldseed,?nextseed;AtomicLong?seed?=?this.seed;do?{ oldseed?=?seed.get();nextseed?=?(oldseed?*?multiplier?+?addend)?&?mask;}?while?(!seed.compareAndSet(oldseed,?nextseed));return?(int)(nextseed?>>>?(?-?bits));}复制代码三:ThreadLocalRandom的简单使用
使用的方法很简单,通过ThreadLocalRandom.current()获取到ThreadLocalRandom实例,码j码然后通过nextInt(),nextLong()等方法获取一个随机数。
代码:
@Testvoid?test()?throws?InterruptedException?{ new?Thread(()->{ ThreadLocalRandom?random?=?ThreadLocalRandom.current();System.out.println(random.nextInt());}).start();new?Thread(()->{ ThreadLocalRandom?random?=?ThreadLocalRandom.current();System.out.println(random.nextInt());}).start();Thread.sleep();}复制代码运行结果:
四:为什么ThreadLocalRandom能在保证线程安全的情况下还能有不错的性能
我们可以看一下ThreadLocalRandom的代码实现。
首先我们很容易看出这是一个饿汉式的单例
/**?Constructor?used?only?for?static?singleton?*/private?ThreadLocalRandom()?{ initialized?=?true;?//?false?during?super()?call}/**?The?common?ThreadLocalRandom?*/static?final?ThreadLocalRandom?instance?=?new?ThreadLocalRandom();复制代码我们可以看到PROBE成员变量代表的是Thread类的threadLocalRandomProbe属性的内存偏移量,SEED成员变量代表的是Thread类的threadLocalRandomSeed属性的内存偏移量,SECONDARY成员变量代表的是Thread类的threadLocalRandomSecondarySeed属性的内存偏移量。
//?Unsafe?mechanicsprivate?static?final?sun.misc.Unsafe?UNSAFE;private?static?final?long?SEED;private?static?final?long?PROBE;private?static?final?long?SECONDARY;static?{ try?{ UNSAFE?=?sun.misc.Unsafe.getUnsafe();Class<?>?tk?=?Thread.class;SEED?=?UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSeed"));PROBE?=?UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomProbe"));SECONDARY?=?UNSAFE.objectFieldOffset(tk.getDeclaredField("threadLocalRandomSecondarySeed"));}?catch?(Exception?e)?{ throw?new?Error(e);}}复制代码可以看到Thread类中确实有这三个属性
Thread类:
@sun.misc.Contended("tlr")//当前Thread的随机种子?默认值是0long?threadLocalRandomSeed;/**?Probe?hash?value;?nonzero?if?threadLocalRandomSeed?initialized?*/@sun.misc.Contended("tlr")//用来标志当前Thread的threadLocalRandomSeed是否进行了初始化?0代表没有,非0代表已经初始化?默认值是0int?threadLocalRandomProbe;/**?Secondary?seed?isolated?from?public?ThreadLocalRandom?sequence?*/@sun.misc.Contended("tlr")//当前Thread的二级随机种子?默认值是0int?threadLocalRandomSecondarySeed;复制代码接下来我们看ThreadLocalRandom.current()方法。
ThreadLocalRandom.current()
ThreadLocalRandom.current()的作用主要是初始化随机种子,并且返回ThreadLocalRandom的实例。
首先通过UNSAFE类获取当前线程的Thread对象的threadLocalRandomProbe属性,看随机种子是否已经初始化。没有初始化,那么调用localInit()方法进行初始化
public?static?ThreadLocalRandom?current()?{ //?获取当前线程的if?(UNSAFE.getInt(Thread.currentThread(),?PROBE)?==?0)localInit();return?instance;}复制代码localInit()
localInit()方法的作用就是初始化随机种子,可以看到代码很简单,就是通过UNSAFE类对当前Thread的threadLocalRandomProbe属性和threadLocalRandomSeed属性进行一个赋值。
static?final?void?localInit()?{ int?p?=?probeGenerator.addAndGet(PROBE_INCREMENT);int?probe?=?(p?==?0)?1?:?p;?//?skip?0long?seed?=?mix(seeder.getAndAdd(SEEDER_INCREMENT));Thread?t?=?Thread.currentThread();UNSAFE.putLong(t,?SEED,?seed);UNSAFE.putInt(t,?PROBE,?probe);}复制代码接下来以nextInt()方法为例,看ThreadLocalRandom是如何生成到随机数的。我们可以看出随机数正是通过nextSeed()方法获取到随机种子,然后通过随机种子而生成。所以重点看nextSeed()方法是如何获取到随机种子的。
public?int?nextInt(int?bound)?{ if?(bound?<=?0)throw?new?IllegalArgumentException(BadBound);int?r?=?mix(nextSeed());int?m?=?bound?-?1;if?((bound?&?m)?==?0)?//?power?of?twor?&=?m;else?{ ?//?reject?over-represented?candidatesfor?(int?u?=?r?>>>?1;?u?+?m?-?(r?=?u?%?bound)?<?0;?u?=?mix(nextSeed())?>>>?1);}return?r;}复制代码nextSeed()
nextSeed()方法的作用是获取随机种子,代码很简单,就是通过UNSAFE类获取当前线程的threadLocalRandomSeed属性,并且将原来的threadLocalRandomSeed加上GAMMA设置成新的threadLocalRandomSeed。
final?long?nextSeed()?{ Thread?t;?long?r;?//?read?and?update?per-thread?seedUNSAFE.putLong(t?=?Thread.currentThread(),?SEED,?r?=?UNSAFE.getLong(t,?SEED)?+?GAMMA);return?r;}复制代码小结:
ThreadLocalRandom为什么线程安全?是因为它将随机种子保存在当前Thread对象的threadLocalRandomSeed变量中,这样每个线程都有自己的源码易经入门课随机种子,实现了线程级别的隔离,所以ThreadLocalRandom也并不需要像Random通过自旋锁和cas来保证随机种子的线程安全性。在高并发的场景下,效率也会相对较高。
注:各位有没有发现ThreadLocalRandom保证线程安全的方式和ThreadLocal有点像呢
需要注意的点:
1.ThreadLocalRandom是单例的。
2.我们每个线程在获取随机数之前都需要调用一下ThreadLocalRandom.current()来初始化当前线程的随机种子。
3.理解ThreadLocalRandom需要对UnSafe类有所了解,它是Java提供的一个可以直接通过内存对变量进行获取和修改的一个工具类。java的CAS也是通过这个工具类来实现的。
原文:“/post/”
七天杀上GitHub榜首!Java并发编程深度解析实战,JUC底层原理揭秘
在多核CPU和多线程技术普及的当今,我们面对的不再是多年前对于线程开启时机的问题。如今,无论是开发人员还是技术开发者,都需要深入了解多线程技术的方方面面。本文将从操作系统原理的角度,全面解析多线程技术,涵盖基础知识到高级进阶,分享作者多年的工作经验和踩坑后的教训。
多线程编程技术已经成为现代软件开发不可或缺的部分。然而,对于很多开发者来说,尽管有各种库和运行环境对操作系统多线程接口的封装,他们仍然面对着复杂的多线程逻辑,甚至只是简单调用库的“业务”程序员。本文旨在从基础出发,深入浅出地讲解多线程技术的各个层面。
本文分为章,从Java线程的实践及原理揭秘开始,逐步深入到synchronized实现原理、volatile解决可见性和有序性问题、J.U.C中的重入锁和读写锁、线程通信中的条件等待机制、J.U.C并发工具集实战、并发编程必备工具、阻塞队列设计原理及实现、并发安全集合原理及源码、线程池设计原理、以及Java并发编程中的异步编程特性。每一章节都基于作者的理财分红软件源码经验总结和踩坑后的教训,为读者提供全面而深入的指导。
如果您对这份手册感兴趣并希望深入学习,欢迎您点赞并关注。获取完整内容的方式非常简单,只需点击下方链接即可。让我们一起探索多线程技术的奥秘,提升编程技能,迈向技术的高峰。
juc是治疗什么的
JUC是Java并发编程的核心工具集。以下是关于JUC的详细解释: 一、JUC概述 Java并发编程是Java编程语言的一个重要部分,而Java并发工具集则为开发者提供了一系列用于并发编程的核心工具。这些工具能够帮助开发者创建多线程应用程序,实现高效的并发处理,提高系统的整体性能和响应能力。 二、JUC的主要组件 JUC包含多个组件,主要包括: 1. 线程池相关类:如ExecutorService、ThreadPoolExecutor等,它们提供了线程池的管理和使用,有效减少创建和销毁线程的开销。 2. 同步辅助类:如CountDownLatch、CyclicBarrier等,这些类提供了同步机制,帮助控制多线程间的协作。 3. 原子变量类:如AtomicInteger、AtomicReference等,这些类提供了原子操作,保证多线程环境下的数据一致性。 4. 阻塞队列及相关操作:如BlockingQueue接口及其实现类,为线程间的数据交换提供了高效的阻塞队列。 三、JUC的应用领域 JUC广泛应用于需要处理并发问题的领域,如: * 高并发Web应用:处理大量用户请求,提高系统吞吐能力。 * 大数据处理:在数据处理和分析过程中,利用并发编程提高处理速度。 * 分布式系统:在分布式环境中,利用并发编程实现各节点间的协同工作。 四、总结 JUC为Java开发者提供了丰富的静态挖矿源码并发编程工具,帮助开发者创建高效、稳定的多线程应用程序。无论是Web应用、大数据处理还是分布式系统,JUC都发挥着重要的作用。熟练掌握JUC的使用,对于提高Java开发者的技能水平具有重要的价值。Java并发指南:JUC中常用的Unsafe和Locksupport
本文转自网络,内容主要介绍Java并发技术中的 Unsafe 类与 Locksupport,它们在Java基础类库以及高性能开发库中扮演着重要角色。虽然Java最初设计时强调安全,但 sun.misc.Unsafe 类提供了直接操作内存和线程的底层能力,被广泛用于JDK内部如java.nio 和 java.util.concurrent等包中。然而,它不建议在生产环境中使用,因为API安全性、灵活性和稳定性较差。
Unsafe 类提供了多种功能,包括内存管理、非常规对象实例化、操作类和对象、数组操作以及多线程同步。它通过一系列方法,如allocateMemory, getInt, monitorEnter等,实现了对Java内存、线程的直接访问与控制。值得注意的是,Unsafe 类中的monitorEnter等方法已被标记为过时,不推荐使用。
Locksupport 是JDK中用来创建锁和其他同步工具类的基础线程阻塞原语,能够实现类似于join()、wait()/notifyAll()的功能,使线程能够自由地阻塞与释放。在Java锁与同步器框架的核心类AQS中,正是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞与唤醒。
Locksupport 提供了park()和unpark()方法来实现线程的阻塞与解除阻塞。这些方法通过与Unsafe类的交互,实现了线程控制的底层实现。值得注意的是,Locksupport的使用必须成对出现,即park()与unpark()配合使用,警务管理系统源码否则可能导致线程阻塞。
在使用Locksupport时,应避免与其他同步机制如wait()、notify()等冲突,因为它们属于不同的实现机制。另外,Locksupport的park()方法可以通过Object blocker参数提供更具体的阻塞信息,帮助开发者定位问题。
总之,Unsafe 类与 Locksupport 提供了对Java内存与线程底层操作的强大能力,它们在提升性能和实现特定功能时具有重要作用,但使用时需谨慎,确保不会引入安全风险或导致系统不稳定。
JUC之CountDownLatch与CyclicBarrier
在java.util.concurrent包中,CountDownLatch与CyclicBarrier是用于线程同步的工具类。CountDownLatch允许一个或多个线程等待直到其他线程完成一组操作。类比于等待所有小伙伴上车后再出发的春游场景,通过使用CountDownLatch,我们可以更简洁地实现这一需求。CountDownLatch包含创建、减计数以及等待计数器为零等方法。
CyclicBarrier则允许一组线程在达到共同屏障点后等待彼此,直至所有线程都执行完毕。这个工具类可以模拟赛跑比赛,所有运动员在起跑线前等待,直到所有运动员准备完毕,比赛正式开始。CyclicBarrier具有构造方法、等待所有线程达到屏障的方法以及重置计数值的能力。
CountDownLatch与CyclicBarrier在使用场景和功能上有所区别。CountDownLatch适用于一个或多个线程等待其他线程执行完毕后继续执行的场景,而CyclicBarrier则适用于一组线程在达到共同点后等待彼此的场景。CountDownLatch强调计数,最终计数为零后线程执行,CyclicBarrier强调共同等待,直到所有线程到达同一屏障点。
总结来说,CountDownLatch与CyclicBarrier均提供了线程同步的功能,但CountDownLatch侧重于计数控制,而CyclicBarrier侧重于共同等待机制。在实际开发中,根据具体场景选择合适的工具类,可以更高效地管理线程同步问题。
八股文JUC知识总结
并发编程,如同一股清流,旨在最大化多核CPU的潜力,提升性能和处理能力,但同时也伴随着一些挑战,如内存泄露、频繁的上下文切换、线程安全难题和死锁的威胁。其中,上下文切换是CPU通过时间片机制切换线程的关键步骤。
探索并行编程的路径多种多样,你可选择四种方式来创建线程:一是继承自Java的Thread类,二是通过实现Runnable接口,三是依赖Callable接口的返回值特性,四是借助Executor工具类的灵活性。Runnable模式虽无返回值,但Callable则提供了返回值处理和异常管理的可能。
线程的生命周期包括五个阶段:新建、就绪、运行、阻塞(包括等待、同步阻塞和其他形式)以及消亡。并发编程的三大基石——原子性、可见性和有序性,是保证并发操作正确性的核心要素,Atomic类、synchronized和Lock接口为我们提供了相应的解决方案。synchronized,作为Java的灵魂关键字,通过互斥、缓存刷新和处理器顺序保证了这三大特性。
深入理解synchronized的底层机制,你会发现它拥有从偏向锁、轻量级锁到重量级锁的升级过程。非竞争时,偏向锁能快速获取,而在竞争中会升级为轻量级锁,自旋尝试不阻塞。然而,当竞争加剧,锁会变为重量级,造成性能损失。volatile关键字则强调可见性和有序性,而非原子性操作。内存屏障则守护数据一致性,防止重排序带来的问题。
对于更高级的锁控制,如ReentrantLock,它提供了可重入、中断选项和公平性选择,比synchronized更为灵活。AQS(AbstractQueuedSynchronizer)则作为基础框架,为构建复杂同步器提供了强大支持。在并发工具中,线程池是必不可少的一部分,它能节省资源、优化响应速度,如FixedThreadPool、ScheduledThreadPool等各有其适用场景。
信号量Semaphore,倒计时器CountDownLatch,以及同步执行器CyclicBarrier,它们各有其特定的并发控制用途。原子类,如AtomicInteger,确保操作的不可分割性。ThreadLocal则为每个线程维护独立的局部变量副本,适用于线程独立数据的处理,但需注意内存泄漏问题。
最后,Thread类的方法如start()启动任务,run()执行操作,yield()让出CPU,join()等待线程结束,而stop()已被弃用。sleep()和isAlive()则是控制线程暂停和判断存活状态的工具。至于同步控制,wait(), notify(), notifyAll()在并发编程中发挥着至关重要的作用。
硬核干货:4W字从源码上分析JUC线程池ThreadPoolExecutor的实现原理
深入剖析JUC线程池ThreadPoolExecutor的执行核心 早有计划详尽解读ThreadPoolExecutor的源码,因事务繁忙未能及时整理。在之前的文章中,我们曾提及Doug Lea设计的Executor接口,其顶层方法execute()是线程池扩展的基础。本文将重点关注ThreadPoolExecutor#execute()的实现,结合简化示例,逐步解析。 ThreadPoolExecutor的核心功能包括固定的核心线程、额外的非核心线程、任务队列和拒绝策略。它的设计巧妙地运用了JUC同步器框架AbstractQueuedSynchronizer(AQS),以及位操作和CAS技术。以核心线程为例,设计上允许它们在任务队列满时阻塞,或者在超时后轮询,而非核心线程则在必要时创建。 创建ThreadPoolExecutor时,我们需要指定核心线程数、最大线程数、任务队列类型等。当核心线程和任务队列满载时,会尝试添加额外线程处理新任务。线程池的状态控制至关重要,通过整型变量ctl进行管理和状态转换,如RUNNING、SHUTDOWN、STOP等,状态控制机制包括工作线程上限数量的位操作。 接下来,我们深入剖析execute()方法。首先,方法会检查线程池状态和工作线程数量,确保在需要时添加新线程。这里涉及一个疑惑:为何需要二次检查?这主要是为了处理任务队列变化和线程池状态切换。任务提交流程中,addWorker()方法负责创建工作线程,其内部逻辑复杂,包含线程中断和适配器Worker的创建。 Worker内部类是线程池核心,它继承自AQS,实现Runnable接口。Worker的构造和run()方法共同确保任务的执行,同时处理线程中断和生命周期的终结。getTask()方法是工作线程获取任务的关键,它会检查任务队列状态和线程池大小,确保资源的有效利用。 线程池关闭操作通过shutdown()、shutdownNow()和awaitTermination()方法实现,它们涉及线程中断、任务队列清理和状态更新等步骤,以确保线程池的有序退出。在这些方法中,可重入锁mainLock和条件变量termination起到了关键作用,保证了线程安全。 ThreadPoolExecutor还提供了钩子方法,允许开发者在特定时刻执行自定义操作。除此之外,它还包含了监控统计、任务队列操作等实用功能,每个功能的实现都是对execute()核心逻辑的扩展和优化。 总的来说,ThreadPoolExecutor的execute()方法是整个线程池的核心,它的实现原理复杂而精细。后续将陆续分析ExecutorService和ScheduledThreadPoolExecutor的源码,深入探讨线程池的扩展和调度机制。敬请关注,期待下文的详细解析。并发编程的基石——AQS类
AQS 简介
AbstractQueuedSynchronizer (AQS) 是JUC包的核心类,用于构建同步工具如ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore和LimitLatch。它抽象了同步器构建过程中的通用关注点,例如资源管理、线程阻塞与唤醒、等待队列等。用户仅需解决同步器资源定义和状态更新两个关键问题。
同步器资源的定义:ReentrantLock表示独占锁,CountDownLatch表示倒计时器,Semaphore表示信号量或令牌,其状态定义了锁可用性、线程等待状态等。ReentrantReadWriteLock则表示共享读锁和独占写锁。
AQS 原理
AQS 管理同步状态并提供API供用户重写以实现自定义同步器。它通过 getState、setState 和 compareAndSetState 操作管理状态,并通过 CLH 队列管理等待线程。
状态管理:使用单个 int 来保存同步状态,提供 API 来读取和更新。
线程阻塞与唤醒:引入 LockSupport 类来实现线程的阻塞和唤醒。
等待队列:基于 CLH 双向循环链表实现,确保同步状态下的线程有序等待和唤醒。
节点定义与队列定义:节点封装线程状态,队列实现线程结构管理,支持取消、唤醒等操作。
AQS 的方法介绍
用户需要重写 tryAcquire、tryRelease 等方法来实现自定义同步器。这些方法提供获取和释放资源的逻辑,无需用户关心线程等待队列的细节。
钩子方法描述:tryAcquire 和 tryRelease 分别用于独占和共享模式下的资源获取和释放。
AQS 提供的一系列模板方法
acquire 和 release 方法是获取和释放资源的顶层入口,acquire 方法自旋尝试获取资源,release 方法则根据资源释放情况唤醒等待线程。
unparkSuccessor 方法用于唤醒等待队列中的下一个线程,确保资源被释放后能尽快分配。
acquireShared 和 releaseShared 方法适用于共享模式,实现资源的获取和释放,并根据情况唤醒等待线程。
总结:AQS 通过抽象和封装,简化了同步器的实现,提供了一套灵活、高效的线程同步机制。用户仅需关注同步资源的定义和状态更新逻辑,其他同步细节如线程等待队列的管理由 AQS 自动处理。