目录:
示例:
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
源码:
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* {@code nThreads} threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
解读一下源码注释:
创建一个线程池,该线程池复用固定数量的线程去操作一个共享的无界队列;
在任何时刻,最多只有nThreads的线程是处于可处理任务的活跃状态。
当所有的线程都处于活跃状态(在处理任务),如果提交了额外的任务,它将会在队列中等待,直到有线程可用。
如果线程在执行期间由于失败而终止,如果需要的话,一个新的线程将会取代它执行后续任务。
线程池中的线程将会一直存在,直到显示的关闭。
这里需要注意,线程的数量是固定的,但是队列大小是无界的(Integer.MAX_VALUE足够大,大到可以任务无界。)
注意这里用的队列:LinkedBlockingQueue,默认队列大小Integer的最大值。
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
代码测试:
package com.java4all.test11;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* Author: yunqing
* Date: 2018/9/19
* Description:
*/
@RestController
@RequestMapping(value = "testThread")
public class TestThread {
/**固定大小的线程池*/
static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
@RequestMapping(value = "parse",method = RequestMethod.GET)
public String parse(){
Future> submit = fixedThreadPool.submit(() -> {
System.out.println("线程名称:" + Thread.currentThread().getName());
});
return null;
}
}
我们设定固定大小为4的线程池,然后用20个并发请求:
线程名称:pool-1-thread-1
线程名称:pool-1-thread-3
线程名称:pool-1-thread-4
线程名称:pool-1-thread-1
线程名称:pool-1-thread-3
线程名称:pool-1-thread-4
线程名称:pool-1-thread-4
线程名称:pool-1-thread-3
线程名称:pool-1-thread-4
线程名称:pool-1-thread-1
线程名称:pool-1-thread-1
线程名称:pool-1-thread-4
线程名称:pool-1-thread-1
线程名称:pool-1-thread-3
线程名称:pool-1-thread-4
线程名称:pool-1-thread-1
线程名称:pool-1-thread-3
线程名称:pool-1-thread-2
线程名称:pool-1-thread-2
线程名称:pool-1-thread-1
由是于队列无界,200 000个也是可以的,但是处理复杂任务时,无界队列可能会让内存爆掉。
示例:
static ExecutorService service = Executors.newSingleThreadExecutor();
源码:
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* {@code newFixedThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
解读一下源码注释:
创建一个线程执行者,它使用单个线程去操作一个无界队列。
(需要注意:如果一个线程由于执行过程中失败导致线程终止,一个新的线程将会取代他,如果需要执行后续任务)
这里使用的队列,也是LinkedBlockingQueue,需要注意。
示例
static ExecutorService service1 = Executors.newCachedThreadPool();
源码:
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
源码解读:
这里,使用的是异步队列SynchronousQueue,而且是非公平的。
查看下源码:
/**
* Creates a {@code SynchronousQueue} with nonfair access policy.
*/
public SynchronousQueue() {
this(false);
}
/**
* Creates a {@code SynchronousQueue} with the specified fairness policy.
*
* @param fair if true, waiting threads contend in FIFO order for
* access; otherwise the order is unspecified.
如果为真,等待线程按照FIFO顺序,否则,顺序是不确定的。
*/
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue() : new TransferStack();
}
测试一下:
/**
* Author: yunqing
* Date: 2018/9/19
* Description:
*/
@RestController
@RequestMapping(value = "testThread")
public class TestThread {
/***/
static ExecutorService service1 = Executors.newCachedThreadPool();
@RequestMapping(value = "parse",method = RequestMethod.GET)
public String parse(){
Future> submit = service1.submit(() -> {
System.out.println("线程名称:" + Thread.currentThread().getName());
});
return null;
}
}
20个并发请求:
线程名称:pool-1-thread-13
线程名称:pool-1-thread-15
线程名称:pool-1-thread-13
线程名称:pool-1-thread-2
线程名称:pool-1-thread-15
线程名称:pool-1-thread-17
线程名称:pool-1-thread-4
线程名称:pool-1-thread-14
线程名称:pool-1-thread-12
线程名称:pool-1-thread-4
线程名称:pool-1-thread-8
线程名称:pool-1-thread-7
线程名称:pool-1-thread-1
线程名称:pool-1-thread-6
线程名称:pool-1-thread-3
线程名称:pool-1-thread-5
线程名称:pool-1-thread-11
线程名称:pool-1-thread-10
线程名称:pool-1-thread-9
线程名称:pool-1-thread-16
注意看,是有线程复用的。
/**
* Author: yunqing
* Date: 2018/9/19
* Description:
*/
@RestController
@RequestMapping(value = "testThread")
public class TestThread {
static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
4, //corePoolSize:线程核心数量,及时处于idle状态,也不会回收
10, //maximumPoolSize:线程数的上限
60, //keepAliveTime:超过这个时间,超过corePoolSize的线程,多余的线程将会被回收
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(300), //任务的排队队列 不显示指定大小,会默认Integer.MAX_VALUE,设置不当容易OOM
new ThreadPoolExecutor.AbortPolicy() //拒绝策略
);
@RequestMapping(value = "parse",method = RequestMethod.GET)
public String parse(){
Future> submit = threadPoolExecutor.submit(() -> {
System.out.println("线程名称:" + Thread.currentThread().getName());
});
return "处理完了";
}
}
package com.java4all.test11;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.*;
/**
* Author: yunqing
* Date: 2018/9/19
* Description:
*/
@RestController
@RequestMapping(value = "testThread")
public class TestThread {
static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
4, //corePoolSize:线程核心数量,及时处于idle状态,也不会回收
10, //maximumPoolSize:线程数的上限
60, //keepAliveTime:超过这个时间,超过corePoolSize的线程,多余的线程将会被回收
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(200), //任务的排队队列 不显示指定大小,会默认Integer.MAX_VALUE,设置不当容易OOM
new ThreadPoolExecutor.AbortPolicy() //拒绝策略
);
@RequestMapping(value = "parse",method = RequestMethod.GET)
public String parse(){
Future> future = threadPoolExecutor.submit(() -> {
Thread.sleep(10000);
System.out.println("线程名称:" + Thread.currentThread().getName());
return Thread.currentThread().getName()+":处理完了数据";
});
Object o = null;
try {
//获取执行结果 如果设置了时间,规定时间内没有处理完,返回结果可能为空
o = future.get(4,TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
System.out.println(o.toString());
return "处理完了";
}
}
future.get()方法,是一个阻塞方法,会等到线程任务执行完了,返回结果;如果设置了时间,会等待到设定的时间,如果超市了还没有计算完成,返回结果可能为null;所以,这里需要注意NPE;
加入我们创建一个如下的线程池 ,他的这些参数是怎么工作的呢?
static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
4, //corePoolSize:线程核心数量,及时处于idle状态,也不会回收
10, //maximumPoolSize:线程数的上限
60, //keepAliveTime:超过这个时间,超过corePoolSize的线程,多余的线程将会被回收
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(200), //任务的排队队列 不显示指定大小,会默认Integer.MAX_VALUE,设置不当容易OOM
new ThreadPoolExecutor.AbortPolicy() //拒绝策略
);
各参数工作步骤如下:
1.刚开始,没有提交任务时,线程池是空的,队列也是空的;
2.提交一个任务;
3.此时,线程池中,因为没有线程,没有达到corePoolSize也就是4,所以新建一个线程来执行这个任务;
4.此时,如果这个任务处理完了,这个线程并不会被销毁,而是进入阻塞状态
5.由于使用的是LinkedBlockingQueue,如果不设置大小,那最大任务数量就是Integer.MAX_VALUE,一直添加任务可能会爆掉内存。
6.3中创建的线程会用阻塞的方式,从LinkedBlockingQueue这个任务队列里获取任务,如果没有任务一直阻塞,来任务了就去执行任务;
7.现在又来了一个任务,如果3中创建的线程还在处理别的任务,那么,此时,会看线程数量是否达到corePoolSize,如果没有,那就新建一个线程来处理;
8.重复以上,直到线程数量达到corePoolSize;
9.此时,如果再添加任务,而且corePoolSize中的线程都在处理任务中,那么,任务会直接压进队列中,直到队列满了;
10.此时,如果corePoolSize的线程都在处理任务,而且队列也满了,任务已经无法入队了;
11.此时,新来了任务,那么会创建新的线程,直到线程数量达到maximumPoolSize;
12.此时,如果maximumPoolSize中所有的线程都在处理任务,而且队列也满了,那新来了任务怎么办?
13.new ThreadPoolExecutor.AbortPolicy() 这个拒绝策略开始起作用了。
14.在上面,线程的数量已经达到了maximumPoolSize,超过corePoolSize,也是会一直阻塞等到获取队列中的任务,如果获取不到,空闲的时间超过了keepAliveTime,那么这个线程就销毁了。
15.可以看到,只有corePoolSize的线程都在处理任务,而且队列满了,才会去创建新的线程直到maximumPoolSize,keepAliveTime才会有作用,所以,如果不设置队列大小,他默认的大小是Integer.MAX_VALUE,那近乎无限的大小,这么多任务让corePoolSize来处理,那是处理不完的,任务会一直积压,内存爆掉。