Java线程池的几种实现方式
来源:互联网 发布:discuz 附件 阿里云 编辑:程序博客网 时间:2024/06/05 06:16
线程池的实现方式是通过Executors类创建几种不同类型的线程池,常用的有newFixedThreadPool(int nThreads),构造方法如下:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());}
第一个参数代表corePoolSize,第二个代表maximumPoolSize,第三个代表keepAliveTime存活时间,最后一个是用队列保存超出的任务。
具体代码:
ExecutorService ec = Executors.newFixedThreadPool(2);ec.submit(new Runnable(){ public void run() { try { Thread.sleep(1000L); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); }});
ec.submit方法调用的是抽象类AbstractExecutorService中的submit方法
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); FutureTask<Object> ftask = new FutureTask<Object>(task, null); execute(ftask); return ftask;}
该方法创建一个未来任务FutureTask
public FutureTask(Runnable runnable, V result) { sync = new Sync(Executors.callable(runnable, result));}
Executors.callable方法如下:
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result);}static final class RunnableAdapter<T> implements Callable<T> {final Runnable task;final T result;RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result;}public T call() { task.run(); return result; }
未来任务FutureTask创建完毕之后, 执行execute(ftask)方法,调用ThreadPoolExecutor类。
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); for (;;) { if (runState != RUNNING) { reject(command); return; } if (poolSize < corePoolSize && addIfUnderCorePoolSize(command)) return; if (workQueue.offer(command)) return; Runnable r = addIfUnderMaximumPoolSize(command); if (r == command) return; if (r == null) { reject(command); return; } // else retry }}
会先执行if (poolSize < corePoolSize && addIfUnderCorePoolSize(command)),因为目前线程数量还小于设定的核心数量。addIfUnderCorePoolSize(command)代码如下:
private boolean addIfUnderCorePoolSize(Runnable firstTask) { Thread t = null; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { if (poolSize < corePoolSize) t = addThread(firstTask); } finally { mainLock.unlock(); } if (t == null) return false; t.start(); return true;}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;}
Worker是ThreadPoolExecutor一个内部类,将要执行的任务包装进Worker中,之后执行t.start(),调用Worker中的run方法。
public void run() { try { Runnable task = firstTask; firstTask = null; while (task != null || (task = getTask()) != null) { runTask(task); task = null; // unnecessary but can help GC } } catch(InterruptedException ie) { // fall through } finally { workerDone(this); }}
执行一次后,进入while循环,getTask方法如下:
Runnable getTask() throws InterruptedException { for (;;) { switch(runState) { case RUNNING: { if (poolSize <= corePoolSize) // untimed wait if core return workQueue.take(); long timeout = keepAliveTime; if (timeout <= 0) // die immediately for 0 timeout return null; Runnable r = workQueue.poll(timeout, TimeUnit.NANOSECONDS); if (r != null) return r; if (poolSize > corePoolSize) // timed out return null; // else, after timeout, pool shrank so shouldn't die, so retry break; } case SHUTDOWN: { // Help drain queue Runnable r = workQueue.poll(); if (r != null) return r; // Check if can terminate if (workQueue.isEmpty()) { interruptIdleWorkers(); return null; } // There could still be delayed tasks in queue. // Wait for one, re-checking state upon interruption try { return workQueue.take(); } catch(InterruptedException ignore) {} break; } case STOP: return null; default: assert false; } }}
newFixedThreadPool创建的数量一直是poolSize 小于等于corePoolSize,所以从队列中获取下一条任务,如果没有则等待,workQueue.take();
下面开始讲newCachedThreadPool,该类的创建方式:Executors.newCachedThreadPool();
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());}
内部生成一个corePoolSize为0,poolSize 为整形最大数,存活时间为60s的线程池。他的执行任务方式和newFixedThreadPool一样,也是ec.submit。我们关心的是如何做到60s后自动回收的。主要在Worker中的getTask方法里。
while (task != null || (task = getTask()) != null) { runTask(task); task = null; // unnecessary but can help GC} switch(runState) { case RUNNING: { if (poolSize <= corePoolSize) // untimed wait if core return workQueue.take(); long timeout = keepAliveTime; if (timeout <= 0) // die immediately for 0 timeout return null; Runnable r = workQueue.poll(timeout, TimeUnit.NANOSECONDS); if (r != null) return r; if (poolSize > corePoolSize) // timed out return null; // else, after timeout, pool shrank so shouldn't die, so retry break; }
getTask方法中,由于corePoolSize为0,所以直接走下面,获取超时时间keepAliveTime,然后从队列中Runnable r = workQueue.poll(timeout, TimeUnit.NANOSECONDS);根据超时时间获取任务,超过时限则break。之后外面run方法的循环结束,线程关闭。
public void run() { try { Runnable task = firstTask; firstTask = null; while (task != null || (task = getTask()) != null) { runTask(task); task = null; // unnecessary but can help GC } } catch(InterruptedException ie) { // fall through } finally { workerDone(this); }}
最后再讲一下定时及延时执行的线程newScheduledThreadPool,创建方式:ScheduledExecutorService ec = Executors.newScheduledThreadPool(int corePoolSize);
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,new DelayedWorkQueue());}
执行任务为:
ec1.scheduleAtFixedRate(new Runnable(){ public void run() { System.out.println("i:"+j+" ********"); }},10, 2, TimeUnit.SECONDS);
10代表首次执行延时10秒执行,之后每2秒执行一次。接着看他们的实现原理。方法如下:
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { if (command == null || unit == null) throw new NullPointerException(); if (period <= 0) throw new IllegalArgumentException(); if (initialDelay < 0) initialDelay = 0; long triggerTime = now() + unit.toNanos(initialDelay); ScheduledFutureTask<?> t = new ScheduledFutureTask<Object>(command, null, triggerTime, unit.toNanos(period)); delayedExecute(t); return t;}ScheduledFutureTask(Runnable r, V result, long ns, long period) { super(r, result); this.time = ns; this.period = period; this.sequenceNumber = sequencer.getAndIncrement();}
创建任务大体相同,将延时时间设置为time,将每次执行时间设置为period。之后执行delayedExecute(t);方法。
private void delayedExecute(Runnable command) { if (isShutdown()) { reject(command); return; } // Prestart a thread if necessary. We cannot prestart it // running the task because the task (probably) shouldn't be // run yet, so thread will just idle until delay elapses. if (getPoolSize() < getCorePoolSize()) prestartCoreThread(); super.getQueue().add(command);}
该方法比较目前的线程数量是否小于设置的核心数量,如果小于,则创建线程,否则加入队列。当我们第一次进入时,肯定是小于的。执行prestartCoreThread()方法。
public boolean prestartCoreThread() { return addIfUnderCorePoolSize(null);}
该方法执行addIfUnderCorePoolSize()方法,和newFixedThreadPool相同,只不过传入的Runnable任务为null,表明只创建个线程被Worker包装,之后将该Runnable任务放入队列中。接着执行Worker的run方法,从getTask中获取任务。
Runnable getTask() throws InterruptedException { for (;;) { switch(runState) { case RUNNING: { if (poolSize <= corePoolSize) // untimed wait if core return workQueue.take(); long timeout = keepAliveTime; if (timeout <= 0) // die immediately for 0 timeout return null; Runnable r = workQueue.poll(timeout, TimeUnit.NANOSECONDS); if (r != null) return r; if (poolSize > corePoolSize) // timed out return null; // else, after timeout, pool shrank so shouldn't die, so retry break; }
这是workQueue.take()的实现类是DelayQueue队列,
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { E first = q.peek(); if (first == null) { available.await(); } else { long delay = first.getDelay(TimeUnit.NANOSECONDS); if (delay > 0) { long tl = available.awaitNanos(delay); } else { E x = q.poll(); assert x != null; if (q.size() != 0) available.signalAll(); // wake up other takers return x; } } } } finally { lock.unlock(); }}
先获取time,第一次设置的10秒,等待10s后返回开始执行任务。执行的run方法是ScheduledThreadPoolExecutor中的run方法。
public void run() { if (isPeriodic()) runPeriodic(); else ScheduledFutureTask.super.run();}
runPeriodic()方法内容:
private void runPeriodic() { boolean ok = ScheduledFutureTask.super.runAndReset(); boolean down = isShutdown(); // Reschedule if not cancelled and not shutdown or policy allows if (ok && (!down || (getContinueExistingPeriodicTasksAfterShutdownPolicy() && !isTerminating()))) { long p = period; if (p > 0) time += p; else time = now() - p; ScheduledThreadPoolExecutor.super.getQueue().add(this); } // This might have been the final executed delayed // task. Wake up threads to check. else if (down) interruptIdleWorkers();}
方法在runAndReset中执行完毕,之后获取每次间隔多少时间执行的参数period,将time设为time+p。这样当再次循环从队列中找任务的时候, long delay = first.getDelay(TimeUnit.NANOSECONDS);
public long getDelay(TimeUnit unit) { long d = unit.convert(time - now(), TimeUnit.NANOSECONDS); return d;}
就是等待2S后执行了。
以上就是newFixedThreadPool、newScheduledThreadPool、newCachedThreadPool的实现原理。
- java线程实现的几种方式
- java中线程池的几种实现方式
- java中线程池的几种实现方式
- Java线程池的几种实现方式
- java中线程池的几种实现方式
- 实现线程的几种方式
- 实现线程同步的几种方式
- 实现线程安全的几种方式
- 实现线程同步的几种方式
- 实现线程同步的几种方式
- java线程同步的几种方式
- Java线程同步的几种方式
- java停止线程的几种方式
- Java-线程创建的几种方式
- java线程的几种方式
- 创建线程池的几种方式
- 线程池的几种创建方式
- (十六)java并发编程--线程的死锁解决方案(生产者和消费者几种实现方式)
- Spring MVC 异步处理请求,提高程序性能
- 列表
- 克隆一个对象——原型模式深入解析
- STM32步进电机加减速
- 重要-- 模板 计蒜客-2017 ACM-ICPC 亚洲区(乌鲁木齐赛区)网络赛J题Our Journey of Dalian Ends (最小费用最大流)
- Java线程池的几种实现方式
- 工厂模式
- 更改yum的默认版本
- BZOJ 2007 海拔 (对偶图 最短路)
- Jmeter Http cookie manager 使用
- 图解算法练习--快速排序(PHP实现)
- 热更新Sophix的初体验
- Nginx+linux 下 yii项目路由配置
- 选择元素出现undefined情况解决方法