关于java线程池

为什么要用线程池

1频繁的new或者销毁线程,是耗费资源和花时间

2如果创建太多的线程,程序内存会很轻易崩溃。

        ExecutorService service = Executors.newFixedThreadPool(6);
   //分配执行任务量
        service.execute(new Runnable() {
            @Override
            public void run() {
            
            }}) 

这是线程池的常用方法,Executors 属于concurrent包下

public class Executors {
    //指定线程
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
        
}
/**ThreadPoolExecutor的一个构造方法*/
 public ThreadPoolExecutor(int corePoolSize/**核心线程数*/,
                              int maximumPoolSize/**最大线程数*/,
                              long keepAliveTime/**活跃时间用于后面shutdown线程*/,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue/**任务队列*/) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

execute方法

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)/*new出新的线程来执行*/) {
        //当前线程数大于corePoolSize,走这里,如果状态满足,加入到workqueue中
        if (runState == RUNNING && workQueue.offer(command)) {
            if (runState != RUNNING || poolSize == 0)
                ensureQueuedTaskHandled(command);
        }
        //如果workqueue满了,执行addIfUnderMaximumPoolSize 或者拒绝
        else if (!addIfUnderMaximumPoolSize(command))
            reject(command); // is shutdown or saturated
    }
}
//如果poolsize小于CorePoolSize
private boolean addIfUnderCorePoolSize(Runnable firstTask) {
    Thread t = null;
    //重入锁
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (poolSize < corePoolSize && runState == RUNNING)
            //就是new出一个线程,来执行任务
            t = addThread(firstTask);       
        } finally {
        mainLock.unlock();
    }
    if (t == null)
        return false;
    //就执行任务
    t.start();
    return true;
}    
//就是new出一个线程,来执行任务
private Thread addThread(Runnable firstTask) {
    Worker w = new Worker(firstTask);
    Thread t = threadFactory.newThread(w); 
    if (t != null) {
        w.thread = t;            
        workers.add(w);
        int nt = ++poolSize;    
        if (nt > largestPoolSize)
            largestPoolSize = nt;
    }
    return t;
}
//当poolsize介于corepoolsize和maxinumpoolsize之间的时候
private boolean addIfUnderMaximumPoolSize(Runnable firstTask) {
    Thread t = null;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        if (poolSize < maximumPoolSize && runState == RUNNING)
            t = addThread(firstTask);
    } finally {
        mainLock.unlock();
    }
    if (t == null)
        return false;
    t.start();
    return true;
}

以上代码是线程池的执行流程

然后看一看线程池的工作机制

上面涉及一个类

Worker w = new Worker(firstTask);
//Worker类源码
private final class Worker implements Runnable {
    private final ReentrantLock runLock = new ReentrantLock();
    private Runnable firstTask;
    volatile long completedTasks;
    Thread thread;
    Worker(Runnable firstTask) {
        this.firstTask = firstTask;
    }
    boolean isActive() {
        return runLock.isLocked();
    }
    void interruptIfIdle() {
        final ReentrantLock runLock = this.runLock;
        if (runLock.tryLock()) {
            try {
        if (thread != Thread.currentThread())
        thread.interrupt();
            } finally {
                runLock.unlock();
            }
        }
    }
    void interruptNow() {
        thread.interrupt();
    }
 
    private void runTask(Runnable task) {
        final ReentrantLock runLock = this.runLock;
        runLock.lock();
        try {
            if (runState < STOP &&
                Thread.interrupted() &&
                runState >= STOP)
            boolean ran = false;
            beforeExecute(thread, task);
            try {
                task.run();
                ran = true;
                afterExecute(task, null);
                ++completedTasks;
            } catch (RuntimeException ex) {
                if (!ran)
                    afterExecute(task, ex);
                throw ex;
            }
        } finally {
            runLock.unlock();
        }
    }
 
    public void run() {
        try {
            Runnable task = firstTask;
            firstTask = null;
           //所以这是一个循环,当firstTask执行完的时候,线程会去不停的取任务
            while (task != null || (task = getTask()) != null) {
                //执行任务
                runTask(task);
                task = null;
            }
        } finally {
            workerDone(this);    
        }
    }
}

Runnable getTask() {
    for (;;) {
        try {
            int state = runState;
            if (state > SHUTDOWN)
                return null;
            Runnable r;
            if (state == SHUTDOWN)  
                r = workQueue.poll();
            else if (poolSize > corePoolSize || allowCoreThreadTimeOut) 
                //从刚才的任务队列中取出任务,并返回
                r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
            else
                r = workQueue.take();
            if (r != null)
                return r;
            if (workerCanExit()) {    
                if (runState >= SHUTDOWN)
                    interruptIdleWorkers();  
                return null;
            }
        } catch (InterruptedException ie) {
        }
    }
}        

Worker继承自Runnable,所以关键是run方法,run中看出,这个方法是while循环,会不停的去拿任务执行。

分割线

平常,在指定线程数的时候,如何衡量指定线程数。

一般程序执行分为IO密集型和CPU密集型

  • CPU密集型:长时间占用cpu  这时候多NEW出一些线程就是狼辉。数量为cpu核数N
  • IO密集型:短暂占用cpu,IO操作占用时间  这样就可以多NEW出一些线程。数量为cpu核数N*

 当任务过多,队列满了后,maxcoresize的线程都处理不了时,会启用线程池的拒绝策略。拒绝策略分四个:

  1. 直接丢弃任务。直接报错。慎用啊
  2. 用当前线程执行,那当前线程都阻塞了 业务也不用执行拉,慎用啊
  3. 删除队列的头部任务,然后重新尝试任务。慎用啊
  4. 直接丢弃任务。不报错。

其实拒绝策略和任务排队策略是相关的,排队策略分:

  1. 有限队列。这就需要指定maxcoresize和拒绝策略。
  2. 无限队列。无限队列,就是队列可以不断扩充,那就不会拒绝了,也不用maxsize参数。linkedblockingqueue

下面是threadpoolExecetor构造函数

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {}

可以指定排队策略,拒绝策略。

默认情况用的LinkedBlockingQueue 为无界队列。默认无限扩充队列长度。最多跑过200多w个任务 单独写了个程序跑。没有什么问题

 

posted @ 2018-10-29 16:55  saveworld_niub  阅读(218)  评论(1编辑  收藏  举报