含源码解析.
1 创建线程四种方式
序号 | 创建方式 | 说明 |
---|---|---|
1 | 继承Thread类,重写run方法 | 无返回,不能直接调用run方法,而是使用start方法,因为,使用run方法,即调用普通方法,不会创建线程 |
2 | 实现Runnable接口,重写run方法 | 无返回,避免多继承局限,面向接口 |
3 | 实现Callable接口,重写call方法 | 有返回,利用FutureTask包装Callable,并作为task传入Thread构造函数 |
4 | 利用线程池 | 有返回 |
2 Usage
2.1 继承Thread类
2.1.1 测试
package basic.datatype.thread;
import java.lang.Thread;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class ThreadTest extends Thread{
public ThreadTest(){}
public void run(){
for(int i = 0; i < 5; i++){
try{
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Thread:" + Thread.currentThread()+ ":" + i );
}
}
public static void main(String[] args){
ThreadTest thread1 = new ThreadTest();
ThreadTest thread2 = new ThreadTest();
thread1.start();
thread2.start();
}
}
- 结果
Thread:Thread[Thread-1,5,main]:0
Thread:Thread[Thread-0,5,main]:0
Thread:Thread[Thread-1,5,main]:1
Thread:Thread[Thread-0,5,main]:1
Thread:Thread[Thread-1,5,main]:2
Thread:Thread[Thread-0,5,main]:2
Thread:Thread[Thread-1,5,main]:3
Thread:Thread[Thread-0,5,main]:3
Thread:Thread[Thread-1,5,main]:4
Thread:Thread[Thread-0,5,main]:4
- Thread.currentThread()
public static native Thread currentThread();
currentThread调用C的本地方法.
返回:当前线程对象
Thread[name, priority, group]
2.1.2 Thread源码
Thread实现Runnable接口.
public
class Thread implements Runnable {
/* Make sure registerNatives is the first thing <clinit> does. */
private static native void registerNatives();
static {
registerNatives();
}
private volatile String name;
private int priority;
private Thread threadQ;
private long eetop;
/* Whether or not to single_step this thread. */
private boolean single_step;
/* Whether or not the thread is a daemon thread. */
private boolean daemon = false;
/*....*/
}
2.1.3 start()方法源码
start方法,原子方法,调用start0本地方法.
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
2.1.4 run方法
Thread实现接口Runnable,重写run方法,继承Thread类同样重写run方法.
@Override
public void run() {
if (target != null) {
target.run();
}
}
2.2 实现Runnable
2.2.1 测试
package basic.datatype.thread;
import java.lang.Runnable;
import java.lang.Thread;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class RunnableTest implements Runnable{
public static int count = 10;
public void run(){
while(count > 0){
try{
Thread.sleep(200);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Thread:" + Thread.currentThread() + ",count:" + count--);
}
}
public static void main(String[] args){
RunnableTest runnableTest1 = new RunnableTest();
Thread thread1 = new Thread(runnableTest1, "线程1");
Thread thread2 = new Thread(runnableTest1);
thread1.start();
thread2.start();
}
}
- 结果
Thread:Thread[线程1,5,main],count:10
Thread:Thread[Thread-0,5,main],count:9
Thread:Thread[线程1,5,main],count:8
Thread:Thread[Thread-0,5,main],count:7
Thread:Thread[线程1,5,main],count:6
Thread:Thread[Thread-0,5,main],count:5
Thread:Thread[线程1,5,main],count:4
Thread:Thread[Thread-0,5,main],count:3
Thread:Thread[线程1,5,main],count:2
Thread:Thread[Thread-0,5,main],count:1
Thread:Thread[线程1,5,main],count:0
实现Runnable即重新实现Thread的部分功能,和继承Thread类一致.
2.2.2 Runnable源码
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
真的好简洁,Runnable只有一个抽象run方法,且无返回值.
2.3 实现Callable
2.3.1 测试
package basic.datatype.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class CallableTest implements Callable<String>{
private int count = 10;
@Override
public String call() throws Exception {
for(int i = count; i > 0; i--) {
System.out.println("Thread:" + Thread.currentThread() + ",count:" + i);
}
return "Empty";
}
public static void main(String[] args) throws InterruptedException, ExecutionException{
Callable<String> callable = new CallableTest();
FutureTask<String> futureTask = new FutureTask<>(callable);
Thread thread1 = new Thread(futureTask);
Thread thread2 = new Thread(futureTask);
thread1.start();
thread2.start();
System.out.println("Future task:" + futureTask.get());
}
}
- 结果
Thread:Thread[Thread-0,5,main],count:10
Thread:Thread[Thread-0,5,main],count:9
Thread:Thread[Thread-0,5,main],count:8
Thread:Thread[Thread-0,5,main],count:7
Thread:Thread[Thread-0,5,main],count:6
Thread:Thread[Thread-0,5,main],count:5
Thread:Thread[Thread-0,5,main],count:4
Thread:Thread[Thread-0,5,main],count:3
Thread:Thread[Thread-0,5,main],count:2
Thread:Thread[Thread-0,5,main],count:1
Future task:Empty
2.3.2 Callable源码
Callable接口,只有一个call方法,有返回值.
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
2.3.3 FutureTask源码
FutureTask实现RunnableFuture接口,构造函数FutureTask(Callable callable)创建任务对象,这里的任务可以自定义为需要的逻辑,作为Thread类参数,最终通过Thread新建线程.
public class FutureTask<V> implements RunnableFuture<V> {
/*
* Revision notes: This differs from previous versions of this
* class that relied on AbstractQueuedSynchronizer, mainly to
* avoid surprising users about retaining interrupt status during
* cancellation races. Sync control in the current design relies
* on a "state" field updated via CAS to track completion, along
* with a simple Treiber stack to hold waiting threads.
*
* Style note: As usual, we bypass overhead of using
* AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
*/
/**
* The run state of this task, initially NEW. The run state
* transitions to a terminal state only in methods set,
* setException, and cancel. During completion, state may take on
* transient values of COMPLETING (while outcome is being set) or
* INTERRUPTING (only while interrupting the runner to satisfy a
* cancel(true)). Transitions from these intermediate to final
* states use cheaper ordered/lazy writes because values are unique
* and cannot be further modified.
*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
/** The underlying callable; nulled out after running */
private Callable<V> callable;
/** The result to return or exception to throw from get() */
private Object outcome; // non-volatile, protected by state reads/writes
/** The thread running the callable; CASed during run() */
private volatile Thread runner;
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;
/**
* Returns result or throws exception for completed task.
*
* @param s completed state value
*/
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @throws NullPointerException if the callable is null
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
/**
* Creates a {@code FutureTask} that will, upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If
* you don't need a particular result, consider using
* constructions of the form:
* {@code Future<?> f = new FutureTask<Void>(runnable, null)}
* @throws NullPointerException if the runnable is null
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
public boolean isCancelled() {
return state >= CANCELLED;
}
public boolean isDone() {
return state != NEW;
}
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try { // in case call to interrupt throws exception
if (mayInterruptIfRunning) {
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally { // final state
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
}
2.4 线程池
2.4.1 固定线程数线程池
创建一个指定工作线程数量的线程池,每提交一个任务就会创建一个工作线程,如果工作线程数量达到线程池初始化数量,将提交的任务存储池队列中.
package basic.datatype.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @authro xindaqi
* @since 2020-10-10
*/
public class FixedPoolTest {
public static void main(String[] args) {
ExecutorService exs = Executors.newFixedThreadPool(3);
for(int i = 0; i < 3; i++) {
exs.submit(
new Runnable(){
@Override
public void run() {
for(int j = 0; j < 2; j++) {
System.out.println("Thread: " + Thread.currentThread());
}
}
}
);
}
exs.shutdown();
}
}
- 结果
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-2,5,main]
Thread: Thread[pool-1-thread-2,5,main]
Thread: Thread[pool-1-thread-3,5,main]
Thread: Thread[pool-1-thread-3,5,main]
2.4.2 单线程线程池
创建一个单线程化的Executor,只创建唯一的工作线程执行任务,只会用唯一的工作线程执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行,如果线程异常结束,会有另一个取代,保证顺序执行
package basic.datatype.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class SinglePoolTest {
public static void main(String[] args) {
ExecutorService exs = Executors.newSingleThreadExecutor();
for(int i = 0; i < 5; i++) {
exs.submit(
new Runnable(){
@Override
public void run() {
for(int j = 0; j < 3; j++) {
System.out.println("Thread: " + Thread.currentThread());
}
}
}
);
}
exs.shutdown();
}
}
- 结果
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
Thread: Thread[pool-1-thread-1,5,main]
2.4.3 缓存线程池
创建可缓存线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程池.
2.4.3.1 直接使用
- execute
package basic.datatype.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.List;
import java.util.ArrayList;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class CachedPoolTest {
public static void main(String[] args) throws Exception{
ExecutorService cachedPool = Executors.newCachedThreadPool();
for(int i = 0; i < 5; i++) {
// final int index = i;
int index = i;
try{
Thread.sleep(index * 100);
}catch(InterruptedException e) {
e.printStackTrace();
}
cachedPool.execute(new Runnable() {
public void run() {
System.out.println("Thread execute:" + Thread.currentThread() +"index: " + index);
}
});
}
}
}
- 结果
Thread execute:Thread[pool-1-thread-1,5,main]index: 0
Thread execute:Thread[pool-1-thread-1,5,main]index: 1
Thread execute:Thread[pool-1-thread-1,5,main]index: 2
Thread execute:Thread[pool-1-thread-1,5,main]index: 3
Thread execute:Thread[pool-1-thread-1,5,main]index: 4
- submit
package basic.datatype.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.List;
import java.util.ArrayList;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class CachedPoolTest {
public static void main(String[] args) throws Exception{
ExecutorService cachedPool = Executors.newCachedThreadPool();
for(int i = 0; i < 5; i++) {
// final int index = i;
int index = i;
try{
Thread.sleep(index * 100);
}catch(InterruptedException e) {
e.printStackTrace();
}
cachedPool.submit(new Runnable() {
public void run() {
for(int j = 0; j < 2; j++){
System.out.println("Thread submit: " + Thread.currentThread() + "index: " + j);
}
}
});
}
}
}
- 结果
Thread submit: Thread[pool-1-thread-1,5,main]index: 0
Thread submit: Thread[pool-1-thread-1,5,main]index: 1
Thread submit: Thread[pool-1-thread-1,5,main]index: 0
Thread submit: Thread[pool-1-thread-1,5,main]index: 1
Thread submit: Thread[pool-1-thread-1,5,main]index: 0
Thread submit: Thread[pool-1-thread-1,5,main]index: 1
Thread submit: Thread[pool-1-thread-1,5,main]index: 0
Thread submit: Thread[pool-1-thread-1,5,main]index: 1
Thread submit: Thread[pool-1-thread-1,5,main]index: 0
Thread submit: Thread[pool-1-thread-1,5,main]index: 1
2.4.3.2 单线程:Future+Callable
package basic.datatype.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class CachedPoolTest {
public static void main(String[] args) throws Exception{
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 结合Future与Callable,创建线程池
Future<String> future = cachedPool.submit(new taskExe(5));
System.out.println("Futrue: " + future.get());
// 关闭线程池,正常服务无需关闭
cachedPool.shutdown();
}
public static class taskExe implements Callable<String> {
private int code;
public taskExe(int code){
this.code = code;
}
@Override
public String call() throws Exception {
for(int i = code; i > 0; i--){
System.out.println("Thread: " + Thread.currentThread() + "i: " + i);
}
return "finished";
}
}
}
- 结果
Thread: Thread[pool-1-thread-1,5,main]i: 5
Thread: Thread[pool-1-thread-1,5,main]i: 4
Thread: Thread[pool-1-thread-1,5,main]i: 3
Thread: Thread[pool-1-thread-1,5,main]i: 2
Thread: Thread[pool-1-thread-1,5,main]i: 1
Futrue: finished
2.4.3.3 多线程:Future+Callable
package basic.datatype.thread;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.List;
import java.util.ArrayList;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class CachedPoolTest {
public static void main(String[] args) throws Exception{
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 线程列表
List<Future<String>> futureLis = new ArrayList<Future<String>>();
for(int i = 0; i < 10; i++) {
Future<String> futureTemp = cachedPool.submit(new taskExe(3));
futureLis.add(futureTemp);
}
for(Future<String> futureLi : futureLis) {
while(!futureLi.isDone()) {
System.out.println("Future: " + futureLi.get());
}
}
// 关闭线程池,正常服务无需关闭
cachedPool.shutdown();
}
public static class taskExe implements Callable<String> {
private int code;
public taskExe(int code){
this.code = code;
}
@Override
public String call() throws Exception {
for(int i = code; i > 0; i--){
System.out.println("Thread: " + Thread.currentThread() + "i: " + i);
}
return "finished";
}
}
}
- 结果
Thread: Thread[pool-1-thread-1,5,main]i: 3
Thread: Thread[pool-1-thread-1,5,main]i: 2
Thread: Thread[pool-1-thread-1,5,main]i: 1
Thread: Thread[pool-1-thread-1,5,main]i: 3
Thread: Thread[pool-1-thread-1,5,main]i: 2
Thread: Thread[pool-1-thread-1,5,main]i: 1
Thread: Thread[pool-1-thread-2,5,main]i: 3
Thread: Thread[pool-1-thread-2,5,main]i: 2
Thread: Thread[pool-1-thread-2,5,main]i: 1
Thread: Thread[pool-1-thread-2,5,main]i: 3
Thread: Thread[pool-1-thread-2,5,main]i: 2
Thread: Thread[pool-1-thread-2,5,main]i: 1
Thread: Thread[pool-1-thread-1,5,main]i: 3
Thread: Thread[pool-1-thread-1,5,main]i: 2
Thread: Thread[pool-1-thread-1,5,main]i: 1
Thread: Thread[pool-1-thread-3,5,main]i: 3
Thread: Thread[pool-1-thread-3,5,main]i: 2
Thread: Thread[pool-1-thread-3,5,main]i: 1
Thread: Thread[pool-1-thread-1,5,main]i: 3
Thread: Thread[pool-1-thread-3,5,main]i: 3
Thread: Thread[pool-1-thread-2,5,main]i: 3
Thread: Thread[pool-1-thread-1,5,main]i: 2
Thread: Thread[pool-1-thread-2,5,main]i: 2
Thread: Thread[pool-1-thread-2,5,main]i: 1
Thread: Thread[pool-1-thread-4,5,main]i: 3
Thread: Thread[pool-1-thread-4,5,main]i: 2
Thread: Thread[pool-1-thread-4,5,main]i: 1
Thread: Thread[pool-1-thread-3,5,main]i: 2
Thread: Thread[pool-1-thread-1,5,main]i: 1
Thread: Thread[pool-1-thread-3,5,main]i: 1
Future: finished
2.4.4 定时线程池
指定长度的线程池,以指定时间和周期执行任务,指定定时和周期任务执行.
2.4.4.1 延迟执行
延迟2秒执行.
package basic.datatype.thread;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.time.LocalDateTime;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class SheduledPoolTest {
public static void main(String[] args) {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(3);
System.out.println("Time start:" + LocalDateTime.now());
ses.schedule(
new Runnable() {
@Override
public void run() {
System.out.println("Delay 2 seconds");
System.out.println("Time end:" + LocalDateTime.now());
}
}, 2, TimeUnit.SECONDS);
ses.shutdown();
}
}
- 结果
Time start:2020-10-10T17:54:24.565
Delay 2 seconds
Time end:2020-10-10T17:54:26.567
2.4.4.2 延迟并按周期执行
延迟2秒,并每隔3秒执行一次.
package basic.datatype.thread;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.time.LocalDateTime;
/**
* @author xindaqi
* @since 2020-10-10
*/
public class SheduledPoolTest {
public static void main(String[] args) {
ScheduledExecutorService ses = Executors.newScheduledThreadPool(3);
System.out.println("Time start:" + LocalDateTime.now());
ses.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
System.out.println("Delay 2 seconds and executive in every 3 seconds.");
System.out.println("Time end:" + LocalDateTime.now());
}
}, 2, 3, TimeUnit.SECONDS);
}
}
- 结果
Time start:2020-10-10T18:12:19.687
Delay 2 seconds and executive in every 3 seconds.
Time end:2020-10-10T18:12:21.698
Delay 2 seconds and executive in every 3 seconds.
Time end:2020-10-10T18:12:24.688
Delay 2 seconds and executive in every 3 seconds.
Time end:2020-10-10T18:12:27.688
Delay 2 seconds and executive in every 3 seconds.
Time end:2020-10-10T18:12:30.688
3 线程池拒绝策略
Spring提供的ThreadPoolExecutor有四种线程拒绝策略,如表3.1所示。
序号 | 策略 | 描述 |
---|---|---|
1 | CallerRunsPolicy | 由调用线程直接执行被丢弃的任务 |
2 | AbortPolicy | 直接丢弃任务,同时抛出RejectedExecutionException异常 |
3 | DiscardPolicy | 直接丢弃任务,不抛出异常,如果线程队列已满,后面提交的任务均被直接丢弃 |
4 | DiscardOldestPolicy | 丢弃旧任务,新任务进入线程队列 |
3.1 CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
3.2 AbortPolicy
/**
* A handler for rejected tasks that throws a
* {@code RejectedExecutionException}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
3.3 DiscardPolicy
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
3.4 DiscardOldestPolicy
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
4 Executors与ThreadPoolExecutor
4.1 Executors隐患
- newFixedThreadPool和SingleThreadPool:堆积的请求队列会造成内存增大,甚至OOM
- newCachedThreadPool和newScheduledThreadPool:最大线程量Integer.MAX_VALUE可能引发OOM
4.1.1 指定线程数
- newFixedThreadPool源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- newSingleThreadPool源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- LinkedBlockingQueue源码
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
由于LinkedBlockingQueue为有最大界的队列,当队列递增时,会造成内存增加.
4.1.2 不指定线程数
- newCachedThreadPool源码
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- newScheduledThreadPool源码
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
- ScheduledThreadPoolExecutor源码
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
最大边界队列,会造成OOM.
4.2 ThreadPoolExecutor
使用ThreadPoolExecutor可控制线程数量,用多少,建多少,通过BlockingQueue指定队列边界,避免资源耗尽.
- ThreadPoolExecutor源码
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
- BlockingQueue源码
public interface BlockingQueue<E> extends Queue<E> {
/*....*/
}
5 小结
5.1 线程池构成
(1)线程池管理器:用于创建并管理线程池;
(2)工作线程:线程池中的线程;
(3)任务接口:每个任务必须实现的接口,用于工作线程调度,即自定义的任务
(4)任务队列:存放待处理的任务,缓冲机制
5.2 线程池特点
序号 | 线程池 | 特点 |
---|---|---|
1 | 固定尺寸线程池 | (1)典型且优秀的线程池,具有线程池提高程序效率和节省创建线程时时间开销的优点; (2)线程池空闲时,即使线程池中没有可运行的任务,不会释放线程; (3)一直占用系统资源; |
2 | 单线程线程池 | (1)保证顺序执行各个任务; (2)在任意给定的时间不会有多个线程活动; |
3 | 缓存线程池 | (1)工作线程的创建数量几乎没有限制(最大为Integer.MAX_VALUE=2^31=2147483648 - 1 = 2147483647),可灵活向线程池中添加线程; (2)如果长时间没有向线程池中提交任务,即出现空闲线程(默认1分钟)超过指定时间,该工作线程自动终止,终止后,若又提交了新的任务,则新建一个工作线程; (3)使用CachedThreadPool,注意控制任务数量,否则,大量线程同时运行,会造成系统瘫痪; |
4 | 定时线程池 | 指定时间和周期执行任务,指定定时和周期任务执行 |
5.3 使用ThreadPoolExecutor创建线程池,而不是Executors
- ThreadPoolExecutor可指定队列边界,避免OOM.
- Executors存在默认的Integer.MAX_VALUE,可能会造成OOM.
5.4 使用线程池原因与作用
5.4.1 原因
- 服务器新建线程硬件资源消耗"较大"
- 服务器新建和销毁线程耗时和资源消耗比处理请求长且多
5.4.2 作用
- 响应快
- 资源消耗相对少
5.5 线程池拒绝策略
Spring提供的ThreadPoolExecutor有四种线程拒绝策略,如下表所示。
序号 | 策略 | 描述 |
---|---|---|
1 | CallerRunsPolicy | 由调用线程直接执行被丢弃的任务 |
2 | AbortPolicy | 直接丢弃任务,同时抛出RejectedExecutionException异常 |
3 | DiscardPolicy | 直接丢弃任务,不抛出异常,如果线程队列已满,后面提交的任务均被直接丢弃 |
4 | DiscardOldestPolicy | 丢弃旧任务,新任务进入线程队列 |
5.6 线程池问题
//TODO
[参考文献]
[1]https://blog.csdn.net/li_mengjun/article/details/78159827
[2]https://blog.csdn.net/weixin_41891854/article/details/81265772
[3]https://www.zhihu.com/question/20944522
[4]https://www.jianshu.com/p/7726c70cdc40
[5]https://blog.csdn.net/qq_34301871/article/details/77913882
[6]https://www.cnblogs.com/aaron911/p/6213808.html
[7]https://blog.csdn.net/ryo1060732496/article/details/88926268