JUC之线程池

编程

解决啥问题

要实现多线程,就要实现Runnable、或者继承Thread,重写run方法并且调用start来启动线程,完了还要销毁,频繁的创建销毁浪费资源,所以就先跑几个线程,让有限的线程来做多个线程的run。

思路

定义线程池

  • coreSize 核心线程个数:只有coreSize个的线程在跑
  • maxSize 最大线程个数:初始化BlockingDeque时使用,调用offer方法时,如果超过这个数量就无法再将线程加入线程池
  • BlockingDeque<Runnable/> queue:存储传进来的线程
  • 运行状态标识位:控制线程池是否关闭
  • 内部类 Worker:线程池中自己的线程,就是Work的run方法来实现传入线程的run方法。由于传入的参数是Runnable所以要调run方法,完全可以是其他自定义的类但是实际执行的方法必须统一。

核心方法

  • 构造函数:接受coreSize、maxSize,初始化maxSize长度的BlockingDeque、创建coreSize个数的Worker
  • 增加线程:往队列里丢线程,这里用offer方法,如果超出长度,会阻塞。
  • 停止线程:修改标志位

测试一把

定义一个实际的线程来模拟

三个(coreSize)核心工作线程,最多能屯十个(maxSize)线程的活,这里我们就刚好跑完十个线程的活

代码

package com.juc;  

import java.util.concurrent.BlockingDeque;

import java.util.concurrent.LinkedBlockingDeque;

/**

* 我的线程池 */public class MyThreadPool {

/**

* 内部维护的队列 */

private BlockingDeque<Runnable> queue;

private boolean isRunning = true;

public MyThreadPool(int coreSize,int maxSize) {

this.queue = new LinkedBlockingDeque<Runnable>(maxSize);

System.out.println("正在创建线程池,核心线程数为" + coreSize);

for (int i = 0; i < coreSize; i++) {

new Thread(new Worker()).start();

}

}

public void addThread(Runnable r,int i) {

queue.offer(r);

}

public void shutDown() {

isRunning = false;

System.out.println("线程池正在关闭。。");

}

class Worker implements Runnable {

@Override

public void run() {

System.out.println("工作线程" + Thread.currentThread().getName() + "正在运行");

while (isRunning||!queue.isEmpty()) {

Runnable thread = queue.poll();

if (thread != null) {

thread.run();

}

}

}

}

public static void main(String[] args) throws InterruptedException {

MyThreadPool myThreadPool = new MyThreadPool(3,10);

for (int i = 1; i <= 10; i++) {

myThreadPool.addThread(new ActualThread(i),i);

}

myThreadPool.shutDown();

}

}

class ActualThread extends Thread {

private int i;

public ActualThread(int i) {

super();

this.i = i;

}

@Override

public void run() {

System.out.println(Thread.currentThread().getName() + "跑第" + i + "个线程任务");

}

}

结果

优化

worker线程的创建时机

当线程池中已实例化完成并创建了三个,但是如果加入的线程只有一个或者根本没有,那么这三个Worker不就白跑了?所以Worker的创建需要由实际线程add进来才触发,有可能一个Worker线程就够了。

拒绝策略

如果需要跑的线程大于maxSize,则需要拒绝加入队列。BlockingDeque的offer方法若是超过数量,则添加失败,return false。如果刚好过几秒queue中的线程已经跑完了,那当前的线程就能添加成功,所以添加线程方法可以使用 offerLast(E e, long timeout, TimeUnit unit) 方法给个缓冲时间。

/**  

* @throws NullPointerException {@inheritDoc}

* @throws InterruptedException {@inheritDoc}

*/public boolean offerLast(E e, long timeout, TimeUnit unit)

throws InterruptedException {

if (e == null) throw new NullPointerException();

Node<E> node = new Node<E>(e);

long nanos = unit.toNanos(timeout);

final ReentrantLock lock = this.lock;

lock.lockInterruptibly();

try {

while (!linkLast(node)) {

if (nanos <= 0)

return false;

nanos = notFull.awaitNanos(nanos);

}

return true;

} finally {

lock.unlock();

}

}

JUC包的线程池

Executor源码分析

类图

阿里规约

阿里的《码出高效:JAVA开发手册》中建议不要直接用Executor调用静态方法来创建线程池,通过ThreadPoolExecutor来创建线程池,更明确线程池的运行规则,规避资源耗尽的风险。

以上是 JUC之线程池 的全部内容, 来源链接: utcz.com/z/513505.html

回到顶部