并发与并行
并发:并发就是指代码逻辑上可以并行,有并行的潜力,但是不一定当前是真的以物理并行的方式运行
例如:在吃饭的时候,来电话了,去接电话,这种方式就是 支持并发
并行:并行是指在同一时刻运行多个程序,比如程序的进程。
例如:程序在同一时刻运行着QQ,微信等程序,是相对于cpu的多核处理来说的,是以物理方式运行的。
线程池
①.线程池的整体结构
上图主要是展示线程池的继承结构和其中用到的队列结构
②.线程池的创建
说起来线程池的创建,就不得不说,ThreadPoolExecutor。创建线程池就是通过new ThreadPoolExecutor()进行创建。下面就说下 ThreadPoolExecutor的几个核心参数。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize:
该线程池中核心线程数最大值。线程池新建线程的时候,如果当前线程总数小于 corePoolSize ,则新建的是核心线程;如果超过corePoolSize,则新建的是非核心线程。核心线程数默认是一直存在于线程池中的,即使啥也不干。如果在任务执行过程中,所有的核心线程都在进行工作,此时创建的线程是非核心线程,非核心线程会加入到队列中处理任务,处理完毕之后就会被销毁。 - maximumPoolSize:该线程池中线程总数的最大值。
- keepAliveTime:
该线程池中非核心线程闲置超时时长。一个非核心线程,如果不干活(闲置状态)的时长,超过这个参数所设定的时长,就会被销毁掉。 - unit:
MILLISECONDS:1毫秒 、SECONDS:秒、MINUTES:分、HOURS:小时、DAYS:天 - workQueue:
该线程池中的任务队列:维护着等待执行的Runnable对象。当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务 - threadFactory:
在创建线程池的时候,默认是使用 Executors.defaultThreadFactory() - handler:拒绝策略。默认是new AbortPolicy();
1、当你设置的任务缓存队列过小的时候,或者说, 你的线程池里面所有的线程都在干活(线程数== maxPoolSize),并且你的任务缓存队列也已经充满了等待的队列, 这个时候,你再向它提交任务,则会抛出这个异常。
2、执行shutdown后再向线程池中添加任务。
创建线程池的方式有很多种,可以通过 new ThreadPoolExecutor()进行创建,也可以通过Executors进行创建。
通过new ThreadPoolExecutor()进行创建
public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6) {
this(var1, var2, var3, var5, var6, Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6, ThreadFactory var7) {
this(var1, var2, var3, var5, var6, var7, defaultHandler);
}
public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6, RejectedExecutionHandler var7) {
this(var1, var2, var3, var5, var6, Executors.defaultThreadFactory(), var7);
}
public ThreadPoolExecutor(int var1, int var2, long var3, TimeUnit var5, BlockingQueue<Runnable> var6, ThreadFactory var7, RejectedExecutionHandler var8) {
this.ctl = new AtomicInteger(ctlOf(-536870912, 0));
this.mainLock = new ReentrantLock();
this.workers = new HashSet();
this.termination = this.mainLock.newCondition();
if (var1 >= 0 && var2 > 0 && var2 >= var1 && var3 >= 0L) {
if (var6 != null && var7 != null && var8 != null) {
this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
this.corePoolSize = var1;
this.maximumPoolSize = var2;
this.workQueue = var6;
this.keepAliveTime = var5.toNanos(var3);
this.threadFactory = var7;
this.handler = var8;
} else {
throw new NullPointerException();
}
} else {
throw new IllegalArgumentException();
}
}
<br/>
通过Executors进行创建
// 创建固定大小的线程池
public static ExecutorService newFixedThreadPool(int var0) {
return new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
}
public static ExecutorService newFixedThreadPool(int var0, ThreadFactory var1) {
return new ThreadPoolExecutor(var0, var0, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), var1);
}
// 创建一个线程的线程池
public static ExecutorService newSingleThreadExecutor() {
return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory var0) {
return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(), var0));
}
// 创建可缓存大小的线程池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue());
}
public static ExecutorService newCachedThreadPool(ThreadFactory var0) {
return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue(), var0);
}
// 创建具有一个线程的,能够延时执行任务和周期的线程池
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory var0) {
return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, var0));
}
// 创建一个能够延时执行任务和周期的线程池
public static ScheduledExecutorService newScheduledThreadPool(int var0) {
return new ScheduledThreadPoolExecutor(var0);
}
public static ScheduledExecutorService newScheduledThreadPool(int var0, ThreadFactory var1) {
return new ScheduledThreadPoolExecutor(var0, var1);
但是,通过Executors创建线程池是不推荐的使用的,原因如下:
newCachedThreadPool() 会默认设置核心线程数为0,线程总数为Integer.MAX_SIZE大小的线程池。
newFixedThreadPool()的时候,new LinkedBlockingQueue()也会设置Integer.MAX_SIZE的队列。
上述2种行为在高并发的情况下会导致出现 OOM异常,因此不推荐使用。如果要创建线程池,直接通过new ThreadPoolExecuor() 创建即可
线程池提交线程
ExecutorService executor = Excutors.newFixedThreadPollExecutor(100);
submit():
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
execute():
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
由源码可以看出,其实调用submit的时候,底层还是调用了execute()方法,只不过submit提交之后是有返回值的,调用是成功,还是失败,都可以获取到
线程池的队列
一般来说,workQueue有以下四种队列类型:
-
SynchronousQueue:(同步队列)
这个队列接收到任务的时候,会直接提交给线程处理,而不保留它(名字定义为 同步队列)。但有一种情况,假设所有线程都在工作怎么办?
这种情况下,SynchronousQueue就会新建一个线程来处理这个任务。所以为了保证不出现(线程数达到了maximumPoolSize而不能新建线程)的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大,去规避这个使用风险。 -
LinkedBlockingQueue(链表阻塞队列)
这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize
参考文章:https://www.jianshu.com/p/50fffbf21b39