线程相关分享
一 线程简介:
1.什么是线程:
1. 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位,同一进程中可以存在多个线程并发执行。对于同一进程中的不同线程将共享该进程的所有系统资源,如虚拟地址,文件操作符,信号处理等等。但多个线程会有各自的调度栈,自己的寄存器环境等。
2.线程的状态介绍:
-
NEW(创建状态): 当线程被实例化创建
-
RUNNABLE(就绪及可运行状态): 当实例化对象调用start()方法后线程处于就绪状态,当cpu轮转获得执行后,线程就为运行状态.
-
BLOCKED (阻塞状态):
(1). 调用了wait()方法,jvm会把该线程放到等待池中(又为WAITING状态)。
(2). 同步阻塞,该线程需要获取同步锁但是同步锁此时被别的线程占用。jvm会将这个线程放置在锁池中。
(3). 运行sleep()或者join()方法
-
TERMINATED (死亡状态):执行完毕
3.线程中sleep()与wait()方法的区别:
- 方法来源不同,wait()方法来自Object类,wait()方法来自Thread类
- 执行中是否释放同步锁,wait()方法在执行过程中会释放同步锁,而sleep()在执行过程中不会释放同步锁。切执行sleep()的线程是可以主动打断的。
- 方法执行过程不同,wait()必须在同步控制的方法内调用,而sleep()可以在任何地方使用.
- sleep()必须捕获异常。
线程安全简介:
线程安全是指多线程访问同一代码,避免产生不确定的结果。编写线程安全的代码主要是依靠线程间同步
1.线程安全:
-
常见的线程安全类:
Vector是线程安全的,ArrayList是线程不安全的
StringBuffer是线程安全的,StringBuilder是线程不安全的
Hashtable是线程安全的,HashMap是线程不安全的
2.并发与并行的区别:
- 并行就是两个任务同时运行(需要多核CPU)
- 并发是指两个任务都在请求运行,而处理器只能接受一个任务,就把这两个任务安排轮转执行,由于时间间隔短,给人感觉就是两个任务同时在运行。
Android中的线程池简介:
1.使用线程池的好处:
-
避免碎片化创建线程和销毁线程,线程池中会有已创建线程,这样可以避免线程的创建及销毁对系统带来的性能消耗。
-
线程池中可以控制线程最大并发数,避免线程间出现抢夺系统资源而导致阻塞的现象。
-
线程池可以对线程进行一个整体管理,包括线程定制执行,循环执行等。
-
在Alibaba的代码规范中强烈推荐使用线程池来对程序内部的线程做出统一化管理,而建议不要使用 new Thread()的方法来随手创建线程。
Inspection info: 线程资源必须通过线程池提供,不允许在应用中自行显式创建线程。 说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("demo-pool-%d").build(); ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName())); singleThreadPool.shutdown();
2.实例化线程池中各个参数的含义
ThreadPoolExecutor的多参构造函数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
hreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize(核心线程数):
线程池中核心线程数其中也包含空闲线程数,空闲线程数会有一个空闲时间间隔(keepAliveTime),当空闲时间超过这个时间间隔则会终止该线程。
maximumPoolSize(最大线程数):
线程池最大容纳数,当活动的线程达到这个最大任务数后,后续新任务添加进来会被阻塞(可以通过设置参数来设置阻塞时的不同处理策略)
keepAliveTime(非核心线程超时时长):
非核心线程闲置超时时长,什么是核心线程,非核心线程的含义可以用公式标明:maximunm - corePoolSize(既 最大容纳数 - 核心线程数). 非核心线程就类比一个临时工,当核心成员干不完任务就会叫上临时工一起,但是任务完成了临时工什么时候辞退就是自己指定了,回到文章,当超过这个时长时,非核心线程就会被回收,但是刚才介绍corePoolSize的时候也说了,如果把allowCoreThreadTimeOut的属性设置为true,keepAliveTime也可以同样对核心线程进行终止操作。
unit:
时间单位
workQueue(任务队列):
线程池中的任务队列(阻塞队列),线程池的execute方法提交的Runnable对象存储在这个队列里面,BlockingQueue是线程安全的,常用的阻塞队列有如下五个 :
(1).LinkedBlockingQueue(链表阻塞队列)
链表阻塞队列,这个队列由一个链表构成,它内部维护了一个数据缓存队列,这个队列按 FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部 是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列获取操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。 当构造这个队列对象时,如果不指定队列容量大小,它的默认容量大小是Integer.MAX_VALUE(无限大),这样就是一个无界队列,除非插入节点会使队列超出容量,否则每次插入后会动态地创建链接节点。
(2).ArrayBlockingQueue(数组阻塞队列)
数组阻塞队列,这是一个有界阻塞队列内部,维护了一个定长数组用来缓存队列中的数据对象,通过两个整型变量来标识队列的头跟尾在数组中的位置,这个队列按 FIFO(先进先出)原则对元素进行排序。队列的头部是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。
此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。
(3).DelayQueue(延迟队列)
延迟队列,它也是一个无界阻塞队列,只有在延迟期满时才能从中提取元素。这个队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回 null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于等于 0 的值时,将发生到期。即使无法使用 take 或 poll 移除未到期的元素,也不会将这些元素作为正常元素对待。例如,size 方法同时返回到期和未到期元素的计数。此队列不允许使用 null 元素。 通常用这个队列来管理一个超时未响应队列。
(4).PriorityBlockingQueue(优先阻塞队列)
优先阻塞队列,它也是一个无界阻塞队列,它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞获取操作。虽然这个队列逻辑上是无界的,但是资源被耗尽时试图执行 add 操作也将失败(导致 OutOfMemoryError)。此类不允许使用null(空)元素。依赖自然顺序的优先级队列也不允许插入不可比较的对象(这样做会导致抛出 ClassCastException)。 在创建队列对象时通过构造函数中的Comparator属性对象来决定优先级。
(5).SynchronousQueue(同步阻塞队列)
同步阻塞队列,一种无缓冲阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要移除元素时,该元素才存在;除非另一个线程试图移除某个元素,否则也不能(使用任何方法)插入元素;也不能迭代队列,因为其中没有元素可用于迭代。队列的头 是尝试添加到队列中的首个已排队插入线程的元素;如果没有这样的已排队线程,则没有可用于移除的元素并且 poll() 将会返回 null。对于其他 Collection (集合)方法(例如 contains),同步队列作为一个空集合这个不允许null(空)元素。
同步队列类似于 CSP 和 Ada 中使用的 rendezvous 信道。它非常适合于传递性设计,在这种设计中,在一个线程中运行的对象要将某些信息、事件或任务传递给在另一个线程中运行的对象,它就必须与该对象同步。
threadFactory:
线程工厂,用于在线程池中创建新线程,线程池设计者提供了两个(其实是一个)线程池工厂给我们使用,一个是defaultThreadFactory(),另一个是privilegedThreadFactory,但是查看源码我发现:
/**
* Legacy security code; do not use.
*/
public static ThreadFactory privilegedThreadFactory() {
return new PrivilegedThreadFactory();
}
设计者说这是遗留的安全代码,叫我们不要使用privilegedThreadFactory…,所以一般线程池工厂我们用的是defaultThreadFactory,用法很简单,直接用Executors.defaultThreadFactory();就可以创建一个默认线程池工厂,或者 继 承 T h r e a d F a c t o r y 自 定 义 属 于 自 己 业 务 逻 辑 的 线 程 工 厂 。 \color{red}{继承ThreadFactory自定义属于自己业务逻辑的线程工厂。} 继承ThreadFactory自定义属于自己业务逻辑的线程工厂。
handler:
这个参数是一个RejectedExecutionHandler对象,它是一个接口,只有rejectedExecution这个方法,这个参数的作用是当线程池由于任务队列已满或别的原因无法执行新任务时,ThreadPoolExecutor就会回调实现了这个接口的类来处理被拒绝任务,它的使用是直接用THreadPoolExecutor.XXX,线程池设计者提供了四个处理方法:
(1).ThreadPoolExecutor.AbortPolicy
直接抛出RejectedExecutionException异常,如果不设置处理策略默认是这个方法进行处理
(2).ThreadPoolExecutor.CallerRunsPolicy
直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务.
(3).ThreadPoolExecutor.DiscardOldestPolicy
放弃最旧的未处理请求,然后重试 execute;如果执行程序已关闭,则会丢弃该任务。
(4).ThreadPoolExecutor.DiscardPolicy
默认情况下直接丢弃被拒绝的任务。
3.线程池的种类与使用场景:
种类 | 底层 | 任务 | 使用场景 |
---|---|---|---|
newCachedThreadPool | 若有则执行,若无则创建,若超则销毁 | 大量短期异步任务 | |
newFixedThreadPool | 定池,时间无限,若无则阻塞 | 执行长期的任务,性能好 | |
newSingleThreadExecutor | 单池单线程,时间无限,阻塞执行 | 单任务队列执行 | |
NewScheduledThreadPool | 定池,时间无限,周期性 | 周期性执行任务的场景 | |
当然,在Alibaba的代码规范中也说过,建议开发者自己制定更适合自己业务的线程池,当然以上几种也最好自己来进行创建,这样更能理解线程池中构造函数参数的含义。
Demo:
一个线程池管理一池的线程
一个task队列等待池中的空闲线程去执行队列中的task, task由生产者加入到队列中,工作线程作为消费者,只要池中有空闲的等待线程在等闲新的任务,该线程就会在task队列中消费任务。
ThreadPoolExecutor :
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue );
创建线程池工厂类:
public class PriorityThreadFactory implements ThreadFactory {
public final int mThreadPrio;
/**
*
*工厂类构造函数,传入优先级
*/
public PriorityThreadFactory(int priority){
this.mThreadPrio = priority;
}
/**
*
*重载父类方法,创建线程
*/
@Override
public Thread newThread(final Runnable runnable) {
Runnable runn = new Runnable() {
@Override
public void run() {
try {
Process.setThreadPriority(mThreadPrio);
}catch (Exception e){
e.printStackTrace();
}
runnable.run();
}
};
return new Thread(runn);
}
}
创建主线程TasksExecutor:
public class MainThreadExecutor implements Executor {
/**
*
* Handler 使用UI线程的Looper
*/
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(Runnable runnable) {
// 执行
handler.post(runnable);
}
}
创建一个优先级枚举类:
public enum ThreadPriority {
/**
* 最低优先级,一般用于预加载数据
*/
LOW,
/**
* 中优先级
*/
MEDIUM,
/**
* 高优先级
*/
HIGHT,
/**
* 立即执行
*/
IMMEDIATE,
}
**PriorityRunnable加入优先级并实现Runnable的方法: **
public class PriorityRunnable implements Runnable {
private final ThreadPriority priority;
/**
*
* 构造函数内传入优先级
*/
public PriorityRunnable(ThreadPriority threadPriority){
this.priority = threadPriority;
}
/**
*
* 实现线程具体异步操作
*/
@Override
public void run() {
}
public ThreadPriority getPriority(){
return this.priority;
}
}
**PriorityThreadPoolExecutor的类来实现优先级并重载其方法 **
public class PriorityThreadPoolExecutor extends ThreadPoolExecutor {
/**
* 构造函数
* @param corePoolSize
* @param maximumPoolSize
* @param keepAliveTime
* @param unit
* @param workQueue 这里我们新new出来一个PriorityBlockingQueue
* @param threadFactory
*/
public PriorityThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new PriorityBlockingQueue<Runnable>(), threadFactory);
}
/**
* 重载复写sumbit方法,在这里面我们使用自己创建的Task类
* @param task
* @return
*/
@Override
public Future<?> submit(Runnable task) {
PriorityFutureTask futureTask = new PriorityFutureTask(((PriorityRunnable) task));
execute(futureTask);
return futureTask;
}
/**
* 自己实现的Task类,并使用自己的Runnable,复写compareTo方法,来调整优先级
*/
public static final class PriorityFutureTask extends FutureTask<PriorityRunnable> implements Comparable<PriorityFutureTask>{
private final PriorityRunnable proRunnable ;
public PriorityFutureTask(PriorityRunnable runnable) {
super(runnable, null);
this.proRunnable = runnable;
}
/**
* 获取到构造函数的线程优先级及下一个优先级,并比对优先级进行线程排序
*/
@Override
public int compareTo(PriorityFutureTask priorityFutureTask) {
ThreadPriority priority1 = proRunnable.getPriority();
ThreadPriority priority2 = priorityFutureTask.proRunnable.getPriority();
return priority2.ordinal() - priority1.ordinal();
}
}
}
**通过DefaultExecutorSupplier.java封装几个线程池的使用,并抛出接口给外部使用: **
public class DefaultExecutorSupplier {
//制定线程池数量,获取当前进程可用数
public static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
//重量级后台任务的线程池
private final ThreadPoolExecutor mForBackgroundTasks;
//轻量级后台任务的线程池
private final ThreadPoolExecutor mForLightWeightBackgroundTasks;
//主线程的线程池
private final Executor mMainThreadExector;
private static DefaultExecutorSupplier mInstance;
/**
* 单例模式返回该类实例化对象
*/
public static DefaultExecutorSupplier getInstance() {
if (null == mInstance) {
synchronized (DefaultExecutorSupplier.class) {
if (null == mInstance) {
mInstance = new DefaultExecutorSupplier();
}
}
}
return mInstance;
}
/**
* 构造函数
* 创建出BackTasks 轻量级Ta sks 主线程Tasks实例化对象
*/
private DefaultExecutorSupplier(){
ThreadFactory backgroundPrioFactory = new PriorityThreadFactory(Process.THREAD_PRIORITY_FOREGROUND);
//BackTasks实例化
//可以进行优先级调整的方法,每种Tasks都可以采用此方法实现
mForBackgroundTasks = new PriorityThreadPoolExecutor(
2,
2,
1,
TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(),
backgroundPrioFactory
);
//轻量级Tasks实例化
mForLightWeightBackgroundTasks = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2,
NUMBER_OF_CORES * 2,
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(),
backgroundPrioFactory);
//主线程Tasks实例化
mMainThreadExector = new MainThreadExecutor();
}
/**
* BackTasks抛出,供外部调用
* @return
*/
public ThreadPoolExecutor getmForBackgroundTasks(){
return mForBackgroundTasks;
}
public ThreadPoolExecutor getmForLightWeightBackgroundTasks(){
return mForLightWeightBackgroundTasks;
}
public Executor forMainThreadTasks(){
return mMainThreadExector;
}
}
封装线程池工具类,供外部使用:
public class ThreadPoolUtils {
/*
*重量级后台任务线程池,添加返回Future便于手动销毁线程
*/
public static Future doSomePriorityBackTasks(final String mes, ThreadPriority priority) {
Future future = DefaultExecutorSupplier.getInstance().getmForBackgroundTasks()
.submit(new PriorityRunnable(priority) {
@Override
public void run() {
}
});
return future;
}
/*
*轻量级后台任务线程池
*/
public static Future doSomeLightWeightBackgroundTasks(final String mes) {
Future future = DefaultExecutorSupplier.getInstance().getmForLightWeightBackgroundTasks()
.execute(new PriorityRunnable(priority) {
@Override
public void run() {
}
});
return future;
}
/*
*主线程任务线程池
*/
public static void doSomeMainThreadWork(final String mes) {
DefaultExecutorSupplier.getInstance().forMainThreadTasks()
.execute(new Runnable() {
@Override
public void run() {
}
});
}
}