Java并发编程之线程池线程回收策略
[TOC]
概述
Java并发编程之线程池源码学习
[TOC]
概述
线程需要的时候要进行创建,不需要的时候需要进行销毁,但是线程的创建和销毁都是一个开销比较大的操作。
虽然我们程序员创建一个线程很容易,直接使用 new Thread() 创建就可以了,但是操作系统做的工作会多很多,它需要发出 系统调用,陷入内核,调用内核 API 创建线程,为线程分配资源等,这一些操作有很大的开销。
所以,在高并发大流量的情况下,频繁的创建和销毁线程会大大拖慢响应速度,那么有什么能够提高响应速度的方式吗?方式有很多,尽量避免线程的创建和销毁是一种提升性能的方式,也就是把线程 复用 起来,因为性能是我们日常最关注的因素。
我们先来通过认识一下 Executor 框架、然后通过描述线程池的基本概念入手、逐步认识线程池的核心类,然后慢慢进入线程池的原理中,带你一步一步理解线程池。
在 Java 中可以通过线程池来达到这样的效果。今天我们就来详细讲解一下 Java 的线程池。
Executor 框架为什么要先说一下 Executor 呢?因为我认为 Executor 是线程池的一个驱动,我们平常创建并执行线程用的一般都是 new Thread().start ...
CPU密集型与IO密集型线程
[TOC]
概述CPU密集型(CPU-bound)CPU密集型也叫计算密集型,程序运行绝大部分的时间都进行CPU的运算,CPU的负载率非常高。 例如一个计算圆周率至小数点一千位以下的程序,在执行的过程当中绝大部份时间用在三角函数和开根号的计算,便是属于CPU密集型的程序。
CPU-bound的程序一般而言CPU占用率相当高。这可能是因为任务本身不太需要访问I/O设备,也可能是因为程序是多线程实现因此屏蔽掉了等待I/O的时间。所以,针对CPU密集型的程序,我们为了更好的压榨CPU的计算力。又因为CPU密集型的程序里面IO读取比较少。理论上我们可以设计如下:
1cpu密集型(CPU-bound)线程池设计最佳线程数=cpu核数或者cpu核数±1
IO密集型(I/O bound)IO密集型指的是系统的CPU性能相对硬盘、内存要好很多,此时,系统运作,大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作,此时CPU Loading并不高。
I/O bound的程序一般在达到性能极限时,CPU占用率仍然较低。这 ...
Java并发编程之线程池拒绝策略
[TOC]
文章参考:https://www.jianshu.com/p/aa420c7df275
概述当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:
1234ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
当Executor已经关闭(即执行了executorService.shutdown()方法后),并且Executor将有限边界用于最大线程和工作队列容量,且已经饱和时,在方法execute()中提交的新任务将被拒绝.在以上述情况下,execute 方法将调用其 RejectedEx ...
03.Java并发编程之synchronized实现原理
文章参考:https://blog.csdn.net/javazejian/article/details/72828483
文章参考:https://www.jianshu.com/p/d53bf830fa09
概述本篇主要是对Java并发中synchronized关键字进行较为深入的探索,这些知识点结合博主对synchronized的个人理解以及相关的书籍的讲解(在结尾参考资料),如有误处,欢迎留言。
线程安全是并发编程中的重要关注点,应该注意到的是,造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据。因此为了解决这个问题,我们可能需要这样一个方案,当存在多个线程操作共享数据时,需要保证同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再进行,这种方式有个高尚的名称叫互斥锁,即能达到互斥访问目的的锁,也就是说当一个共享数据被当前正在访问的线程加上互斥锁后,在同一个时刻,其他线程只能处于等待的状态,直到当前线程处理完毕释放该锁。
在 Java 中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchr ...
01.Java并发编程之理论基础知识
概述我们学习一下Java的线程的状态:
初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
阻塞(BLOCKED):表示线程阻塞于锁。
等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
终止(TERMINATED):表示该线程已经执行完毕。
这6种状态定义在Thread类的State枚举中,可查看源码进行一一对应。
1234567891011public enum State { NEW, RUNNABLE, ...
04.Java并发编程之Volatile关键字学习
文章参考:http://www.cnblogs.com/dolphin0520/p/3920373.html
文章参考:https://www.cnblogs.com/paddix/p/5428507.html
概述volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在Java 5之后,volatile关键字才得以重获生机。
在多线程并发编程中,synchronize和volatile都扮演着重要的角色。
volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情。由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识。
一.内存模型的相关概念大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入。由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存在一个问题,由于CPU执行速度很快,而从内存读取数据和向内存写入数据的过 ...
05.Java并发编程之ReentrantLock学习
文章参考:https://cloud.fynote.com/share/d/7057
概述ReentrantLock和Synchronized关键字的区别
synchronized同步锁,锁升级,但是synchronized只有升级,没有降级,锁竞争激烈,不推荐synchronized
ReentrantLock同步锁,内部是基于CAS和AQS实现的,在锁竞争比较激烈时,推荐使用ReentrantLock
ReentrantLock基本使用(可重入锁):
获取锁:ReentrantLock对象.lock();
释放锁:ReentrantLock对象.unlock();
CAS、AQS概念2.1 CAS(乐观锁实现方式)Compare And Swap,是针对一个值进行修改(原子性)
在Java中提供了Unsafe类实现了CAS的操作。
ABA问题:添加版本号。
CAS自旋次数过多:
synchronized基于自适应自旋锁解决。
LongAdder基于Cell[],在CAS实现失败,将数据扔到Cell[]中,后期再添加
劣势:CAS只能保证修改一个值的时候,是原子性的。CAS无法直 ...
06.Java并发编程之Semaphore基础学习
文章转自:https://juejin.im/post/6844903635751534606
概述Semaphore(信号量)是用来控制同时访问特定资源的线程数量,通过协调各个线程以保证合理地使用公共资源。Semaphore可以用作流量控制,特别是公共资源有限的应用场景,比如数据库的连接。
Semaphore主要用于管理信号量,同样在创建Semaphore对象实例的时候通过传入构造参数设定可供管理的信号量的数值。
简单说,信号量管理的信号就好比令牌,构造时传入令牌数量,也就是Semaphore控制并发的数量。
线程在执行并发的代码前要先获取信号(通过aquire函数获取信号许可),执行后归还信号(通过release方法归还),每次acquire信号成功后,Semaphore可用的信号量就会减一,同样release成功之后,Semaphore可用信号量的数目会加一,如果信号量的数量减为0,acquire调用就会阻塞,直到release调用释放信号后,aquire才会获得信号返回。
使用方法一个应用程序要读取几万个文件的数据,由于都是IO密集型任务,所以可以启动几十个(例如10)个线程并 ...
Android中PendingIntent基础学习
[TOC]
概述在Android中,我们常常使用PendingIntent来表达一种“留待日后处理”的意思。从这个角度来说,PendingIntent可以被理解为一种特殊的异步处理机制。不过,单就命名而言,PendingIntent其实具有一定误导性,因为它既不继承于Intent,也不包含Intent,它的核心可以粗略地汇总成四个字——“异步激发”。
很明显,这种异步激发常常是要跨进程执行的。比如说A进程作为发起端,它可以从系统“获取”一个PendingIntent,然后A进程可以将PendingIntent对象通过binder机制“传递”给B进程,再由B进程在未来某个合适时机,“回调”PendingIntent对象的send()动作,完成激发。
PendingIntent 是 Android 提供的一种用于外部程序调起自身程序的能力,生命周期不与主程序相关。外部程序通过 PendingIntent 只能调用起三种组件:Activity、Service、Broadcast。
PendingIntent 的使用场景有三个:使用 AlarmManager 设定闹钟、在系统状态栏显示 Not ...