java并发编程
文章平均质量分 51
java并发编程
八十岁老将
嘿嘿
展开
-
java并发学习35:自定义线程池
步骤1:自定义拒绝策略接口@FunctionalInterface// 拒绝策略interface RejectPolicy <T> { void reject(BlockingQueue<T> queue, Ttask);}步骤2:自定义任务队列class BlockingQueue <T> { // 1. 任务队列 private Deque<T> queue = new ArrayDeque<>(); .原创 2021-01-28 12:52:38 · 92 阅读 · 0 评论 -
java并发学习34:享元模式
1、简介定义:当需要重用数量有限的同一类对象时2、体现2.1 包装类所有的包装类都提供了valueOf方法,例如Long的valueOf会缓存-128~127之间的long对象,在这个范围之间会重用对象,大于这个范围,才会新建Long对象。2.2 String串池2.3 BigDecimal,BigInteger3、自定义连接池4、final原理设置final变量的原理:final变量的赋值也会通过putfield指令来完成,在这条指令之后也会加入写屏障,保证在其他线程读到它的值时不会出现原创 2021-01-28 12:51:50 · 105 阅读 · 1 评论 -
java并发学习33:不可变对象
1、不可变对象使用DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");for (inti=0; i<10; i++) { new Thread(() -> { LocalDate date = dtf.parse("2018-10-01", LocalDate::from); log.debug("{}", date); }).start();}2、设计原创 2021-01-28 12:51:19 · 86 阅读 · 0 评论 -
java并发学习32:unsafe使用
1、介绍Unsafe 对象提供了非常底层的,操作内存、线程的方法,Unsafe 对象不能直接调用,只能通过反射获得public class UnsafeAccessor { static Unsafeunsafe; static { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true);原创 2021-01-28 12:50:47 · 170 阅读 · 0 评论 -
java并发学习31:LongAdder原理
1、介绍LongAdder 是并发大师 @author Doug Lea (大哥李)的作品,设计的非常精巧LongAdder 类有几个关键域// 累加单元数组, 懒惰初始化transientvolatileCell[] cells;// 基础值, 如果没有竞争, 则用 cas 累加这个域transientvolatilelongbase;// 在 cells 创建或扩容时, 置为 1, 表示加锁transientvolatileintcellsBusy...原创 2021-01-28 12:50:15 · 134 阅读 · 0 评论 -
java并发学习30:cas操作,原子整数,原子引用等
class AccountSafe implements Account { private Atomic Integer balance; public AccountSafe(Integerbalance) { this.balance = new AtomicInteger(balance); } @Override public Integer getBalance() { returnbalance.get();原创 2021-01-27 12:22:55 · 149 阅读 · 0 评论 -
java并发学习29:volatile原理
1、概述volatile的底层实现原理是内存屏障,Memory Barrier(Memory Fence)对volatile变量的写指令后会加入写屏障对volatile变量的读指令前会加入读屏障2、如何保证可见性写屏障(sfence)保证在该屏障之前的,对共享变量的改动,都同步到主存当中public void actor2(I_Result r) { num = 2; ready = true;//ready是volatile赋值带写屏障 //写屏障}读屏障(l原创 2021-01-27 12:20:58 · 87 阅读 · 0 评论 -
java并发学习28:有序性
1、有序性指令重排:JVM 会在不影响正确性的前提下,可以调整语句的执行顺序。2、鱼罐头的故事加工一条鱼需要50分钟,只能一条鱼,一条鱼顺序加工……可以将每个鱼罐头的加工流程细分为5个步骤:去鳞清洗10分钟蒸煮沥水10分钟加注汤料10分钟杀菌出锅10分钟真空封罐10分钟即使只有一个工人,最理想的情况是:他能够在10分钟内同时做好这5件事,因为对第一条鱼的真空装罐,不会影响对第二条鱼的杀菌出锅……3、指令重排序优化事实上,现代处理器会设计为一个时钟周期完成一条执行时间最长的cp原创 2021-01-27 12:19:41 · 157 阅读 · 0 评论 -
java并发学习27:犹豫模式
1、犹豫模式Balking(犹豫)模式用在一个线程发现另一个线程或本线程已经做了某一件相同的事,那么 本线程就无需再做了,直接结束返回。class Test { //监控线程 private Thread monitorThread; //停止标记 private boolean stop = false; //判断是否执行过start方法 private boolean starting = false; //启动监控线程 pu原创 2021-01-27 12:18:28 · 132 阅读 · 0 评论 -
java并发学习26:两阶段终止模式
1、volatile改进class Test { private volatile boolean stop = false; //启动监控线程 public void start() { monitorThread = new Thread(() -> { while(true) { Thread current = Thread.currentThread();原创 2021-01-27 12:17:38 · 77 阅读 · 0 评论 -
java并发学习25:可见性
1、Java 内存模型JMM 即 Java Memory Model,它定义了主存、工作内存抽象概念,底层对应着 CPU 寄存器、缓存、硬件内存、CPU 指令优化等。JMM 体现在以下几个方面原子性 - 保证指令不会受到线程上下文切换的影响可见性 - 保证指令不会受 cpu 缓存的影响有序性 - 保证指令不会受 cpu 指令并行优化的影响2、可见性例子:退不出的循环static boolean run = true;public static void main(String[] arg原创 2021-01-27 12:17:17 · 154 阅读 · 0 评论 -
java并发学习24:固定运行顺序模式
1、顺序输出比如,必须先2后1。wait与notify实现static final Object lock = new Object();//表示t2是否运行过static boolean t2runned = false;public static void main(String[] args) { Thread t1 = new Thread(() -> { synchronized (lock) { while (!t2runned)原创 2021-01-27 12:16:07 · 166 阅读 · 0 评论 -
java并发学习23:ReentrantLock介绍使用
1、与synchronized相比可中断可以设置超时时间可以设置为公平锁支持多个条件变量与synchronized一样,都支持可重入基本语法:// 获取锁reentrantLock.lock();try { // 临界区} finally { // 释放锁 reentrantLock.unlock();}2、可重入可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁如果是不可重入锁,那么第二次获得锁时,自己也原创 2021-01-27 12:15:30 · 103 阅读 · 0 评论 -
java并发学习22:多把锁与活跃性
1、多把锁一间大屋子有两个功能:睡觉、学习,互不相干。现在小南要学习,小女要睡觉,但如果只用一间屋子(一个对象锁)的话,那么并发度很低解决方法是准备多个房间(多个对象锁)synchronized(bedRoom) {}synchronized(studyRoom) {}2、死锁有这样的情况:一个线程需要同时获取多把锁,这时就容易发生死锁t1 线程获得A对象锁,接下来想获取B对象的锁t2 线程获得B对象锁,接下来想获取A对象的锁3、定位死锁检测死锁可以使用 jconsole工具,或原创 2021-01-27 12:14:52 · 132 阅读 · 0 评论 -
java并发学习21:线程状态转换
1、情况 1 NEW --> RUNNABLE当调用t.start()方法时,由NEW --> RUNNABLE2、情况 2 RUNNABLE <–> WAITINGt 线程用synchronized(obj)获取了对象锁后调用obj.wait()方法时,t 线程从RUNNABLE --> WAITING调用obj.notify(),obj.notifyAll(),t.interrupt()时竞争锁成功,t 线程从WAITING --> RUN.原创 2021-01-27 12:13:51 · 80 阅读 · 0 评论 -
java并发学习20:park与unpark
1、基本使用它们是 LockSupport 类中的方法// 暂停当前线程LockSupport.park();// 恢复某个线程的运行LockSupport.unpark(暂停线程对象)先 park 再 unpark2、特点与 Object 的 wait & notify 相比wait,notify 和 notifyAll 必须配合 Object Monitor 一起使用,而 park,unpark 不必park & unpark 是以线程为单位来【阻塞】和【唤醒】线原创 2021-01-26 16:37:53 · 169 阅读 · 0 评论 -
java并发学习19:生产者、消费者模式
1、定义与前面的保护性暂停中的GuardObject 不同,不需要产生结果和消费结果的线程一一对应消费队列可以用来平衡生产和消费的线程资源生产者仅负责产生结果数据,不关心数据该如何处理,而消费者专心处理结果数据消息队列是有容量限制的,满时不会再加入数据,空时不会再消耗数据JDK中各种阻塞队列,采用的就是这种模式2、实现class Message { private int id; private Object value; public Message(int原创 2021-01-26 16:36:55 · 77 阅读 · 0 评论 -
java并发学习18:保护性暂停模式
1、定义保护性暂停,即Guarded Suspension,用在一个线程等待另一个线程的执行结果有一个结果需要从一个线程传递到另一个线程,让他们关联同一个GuardedObject如果有结果不断从一个线程到另一个线程那么可以使用消息队列(生产者/消费者)jdk中,Join的实现,Future的实现,采用的就是此模式因为要等待另一方的结果,因此归类到同步模式2、实现class GuardedObject { //结果 private Object response;原创 2021-01-26 16:36:14 · 131 阅读 · 0 评论 -
java并发学习17:wait与notify
1、问题引入2、wait/notify原理Owner线程发现条件不满足,调用wait方法,即可进入WaitSet变为WAITING状态BLOCKED和WAITING的线程都处于阻塞状态,不占用CPU时间片BLOCKED线程会在Owner线程释放锁时唤醒WAITING线程会在Owner线程调用notify或notifyAll时唤醒,但唤醒后并不意味者立刻获得锁,仍需进入EntryList重新竞争3、相关方法wait()让进入object监视器的线程到waitSet等待notify()原创 2021-01-26 16:35:15 · 130 阅读 · 0 评论 -
java并发学习16:偏向锁
1、偏向锁轻量级锁在没有竞争时(就自己这个线程),每次重入仍然需要执行cas操作。java6中引入了偏向锁来做进一步优化:只有第一次使用cas将线程id设置到对象的Mark Word头,之后发现这个线程Id是自己的就表示没有竞争,不用重新cas。以后只要不发生竞争,这个对象就归该线程所有例如:static final Object obj = new Object();public synchronized static void m1() {}public synchronized stat原创 2021-01-26 16:34:23 · 261 阅读 · 0 评论 -
java并发学习15:自旋优化
1、自旋优化重量级锁竞争的时候,还可以使用自旋来进行优化,如果当前线程自旋成功(即这时候持锁线程已经退出了同步块,释放了锁),这时当前线程就可以避免阻塞。自旋重试成功的情况自旋重试失败的情况java6之后自旋锁是自适应的,比如对象刚刚的一次自旋操作成功过,那么认为这次自旋成功的可能性会高,就多自旋几次;反之,就少自旋甚至不自旋,总之,比较智能自旋会占用cpu时间,单核cpu自旋是浪费,多核cpu自旋才能发挥优势。java7之后不能控制是否开启自旋功能...原创 2021-01-26 16:32:42 · 349 阅读 · 0 评论 -
java并发学习14:锁膨胀
1、锁膨胀如果在尝试加轻量级锁的过程中,CAS操作无法成功,这时一种情况就是有其它线程为此对象加上了轻量级锁(有锁竞争),这时需要进行锁膨胀,将轻量级锁变成重量级锁。static Object obj = new Object();public static void method1() { synchronized(obj) { //同步块 }}当Thread-1进行轻量级加锁时,Thread-0已经对该对象加了轻量级锁这时Thread-1加轻量级锁失败,进入锁膨原创 2021-01-26 16:31:53 · 99 阅读 · 0 评论 -
java并发学习13:轻量级锁
1、轻量级锁使用场景:如果一个对象虽然有多线程访问,但多线程访问的时间是错开的(也就是没有竞争),那么可以使用轻量级锁来优化轻量级锁对使用者是透明的,即语法仍然是synchronized假设有两个方法同步块,利用同一个对象加锁static final Object obj = new Object();public static void method1() { synchronized(obj) { //同步块A method2(); }}publi原创 2021-01-26 16:30:59 · 924 阅读 · 1 评论 -
java并发学习12:问题引入
问题引入故事角色老王 - JVM小南 - 线程小女 - 线程房间 - 对象房间门上 - 防盗锁 - Monitor房间门上 - 小南书包 - 轻量级锁房间门上 - 刻上小南大名 - 偏向锁批量重刻名 - 一个类的偏向锁撤销到达 20 阈值不能刻名字 - 批量撤销该类对象的偏向锁,设置该类不可偏向小南要使用房间保证计算不被其它人干扰(原子性),最初,他用的是防盗锁,当上下文切换时,锁住门。这样,即使他离开了,别人也进不了门,他的工作就是安全的。但是,很多情况下没人跟他来竞争房间的使原创 2021-01-26 16:29:11 · 171 阅读 · 0 评论 -
java并发学习11:java对象头与Monitor锁
1、java对象头在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。普通对象:数组对象:Mark Word 结构为:64 位虚拟机 Mark Word:2、Monitor(锁)Monitor被翻译为监视器或管程每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象头的Mark Wordd中就被设置指向Monitor对象原创 2021-01-26 16:28:48 · 692 阅读 · 0 评论 -
Java并发学习10:线程安全分析
1、变量1.1 成员变量和静态变量如果它们没有共享,则线程安全如果它们被共享了,根据它们的状态是否能够改变,又分两种情况如果只有读操作,则线程安全如果有读写操作,则这段代码是临界区,需要考虑线程安全1.2 局部变量局部变量是线程安全的但局部变量引用的对象则未必如果该对象没有逃离方法的作用访问,它是线程安全的如果该对象逃离方法的作用范围,需要考虑线程安全2、常见线程安全类StringInteger等包装类StringBufferRandomVectorHa原创 2021-01-25 18:15:52 · 59 阅读 · 0 评论 -
java并发学习9:synchronized
1、互斥解决临界区问题阻塞式的解决方案:synchronized,Lock非阻塞式的解决方案:原子变量使用阻塞式的解决方案:synchronized,来解决上述问题,即俗称的对象锁,它采用互斥的方式让同一时刻至多只有一个线程能持有对象锁,其它线程再想获取这个对象锁时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文切换。注意:虽然 java 中互斥和同步都可以采用 synchronized 关键字来完成,但它们还是有区别的://互斥是保证临界区的竞态原创 2021-01-25 18:15:11 · 82 阅读 · 0 评论 -
java并发学习8:问题引入
1、小故事老王(操作系统)有一个功能强大的算盘(CPU),现在想把它租出去,赚一点外快小南、小女(线程)来使用这个算盘来进行一些计算,并按照时间给老王支付费用但小南不能一天24小时使用算盘,他经常要小憩一会(sleep),又或是去吃饭上厕所(阻塞 io 操作),有时还需要一根烟,没烟时思路全无(wait)这些情况统称为(阻塞)在这些时候,算盘没利用起来(不能收钱了),老王觉得有点不划算另外,小女也想用用算盘,如果总是小南占着算盘,让小女觉得不公平于是,老王灵机一动,想了个原创 2021-01-25 18:14:15 · 116 阅读 · 0 评论 -
java并发学习7:线程的状态
1、五种状态操作系统层面描述初始状态:仅是在语言层面创建了线程对象,还未与操作系统线程关联可运行状态(就绪状态):指该线程已经被创建(与操作系统线程关联),可以由 CPU 调度执行运行状态:指获取了 CPU 时间片运行中的状态当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,会导致线程的上下文切换阻塞状态1.如果调用了阻塞 API,如 BIO 读写文件,这时该线程实际不会用到 CPU,会导致线程上下文切换,进入【阻塞状态】2.等 BIO 操作完毕,会由操作系原创 2021-01-25 18:12:47 · 53 阅读 · 0 评论 -
java并发学习6:常见方法二
1、parkLockSupport.park();//让线程停下来2、打断park打断之后在使用park停止相思程就不行了,要想使park在生效,要使interrupted()标记为false.使用isInterrupted()方法,会抹去当前的状态,就标记就成false了,park也就生效了。Threadt1=newThread(() ->{ log.debug("park..."); LockSupport.park(); log.debug("unpark..原创 2021-01-25 18:11:54 · 60 阅读 · 0 评论 -
java并发学习5:两阶段终止模式
两阶断终止就是在一个线程优雅的终止另外一个线程,优雅的意思就是给被打断的那个线程一个料理后事的机会。注意:不能用stop方法直接停止线程,stop方法会真正的杀死线程,如果这个时候线程锁住了共享资源,那么当它被杀死后就没有机会释放锁了,其他线程也不能在获得锁了。1、基本流程2、代码实现while(true) { Thread current = Thread.currentThread(); if(current.isInterrupted()){ log.de.原创 2021-01-25 18:11:24 · 152 阅读 · 1 评论 -
java并发学习4:常见方法
1、常见方法方法名static功能说明注意start()启动一个新线程,在新的线程运行 run 方法中的代码start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateExceptionrun()新线程启动后会调用的方法如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法原创 2021-01-25 18:10:28 · 62 阅读 · 0 评论 -
java并发学习3:线程的创建与运行原理
运行一个java程序的时候就已经启动了一个线程,主线程,如果还需要开启线程的话,就需要创建新的线程。1、创建线程直接使用Thread类// 创建线程对象Thread t = new Thread() { public voidrun() { // 要执行的任务 }};//为线程指定名称t.setName("t1)// 启动线程t.start();Runnable 配合 Thread创建(推荐使用)/*把线程和任务分开Thread .原创 2021-01-25 18:07:57 · 99 阅读 · 0 评论 -
java并发学习2:线程的应用
1、同步异步以调用方角度来讲,如果需要等待结果返回,才能继续运行就是同步不需要等待结果返回,就能继续运行就是异步设计多线程可以让方法执行变为异步的(即不要巴巴干等着)比如说读取磁盘文件时,假设读取操作花费了 5 秒钟,如果没有线程调度机制,这 5 秒 cpu 什么都做不了,其它代码都得暂停…比如在项目中,视频文件需要转换格式等操作比较费时,这时开一个新线程处理视频转换,避免阻塞主线程tomcat 的异步 servlet 也是类似的目的,让用户线程处理耗时较长的操作,避免阻塞原创 2021-01-25 18:06:49 · 66 阅读 · 0 评论 -
java并发学习1:进程与线程,并发与并行
1、进程与线程进程负责调度,分配资源,加载这些指令的,线程是实现这些指令的最小单位1.1 进程程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的。当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。进程就可以视为程序的一个实例。大部分程序可以同时运行多个实例进程(例如记事本、画图、浏览器等),也有的程序只能启动一个实例进程(例如原创 2021-01-25 18:06:15 · 82 阅读 · 0 评论