Java基础系列:线程及线程池及源码分析

含源码解析.

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所示。

序号策略描述
1CallerRunsPolicy由调用线程直接执行被丢弃的任务
2AbortPolicy直接丢弃任务,同时抛出RejectedExecutionException异常
3DiscardPolicy直接丢弃任务,不抛出异常,如果线程队列已满,后面提交的任务均被直接丢弃
4DiscardOldestPolicy丢弃旧任务,新任务进入线程队列

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有四种线程拒绝策略,如下表所示。

序号策略描述
1CallerRunsPolicy由调用线程直接执行被丢弃的任务
2AbortPolicy直接丢弃任务,同时抛出RejectedExecutionException异常
3DiscardPolicy直接丢弃任务,不抛出异常,如果线程队列已满,后面提交的任务均被直接丢弃
4DiscardOldestPolicy丢弃旧任务,新任务进入线程队列

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天然玩家

坚持才能做到极致

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值