并发编程专题六-线程池的使用与原理,java软件工程师面试题

// 工作线程组

private WorkThread[] workThreads;

// 任务队列,作为一个缓冲

private final BlockingQueue taskQueue;

private final int worker_num;//用户在构造这个池,希望的启动的线程数

// 创建具有默认线程个数的线程池

public MyThreadPool() {

this(WORK_NUM,TASK_COUNT);

}

// 创建线程池,worker_num为线程池中工作线程的个数

public MyThreadPool(int worker_num,int taskCount) {

if (worker_num<=0) worker_num = WORK_NUM;

if(taskCount<=0) taskCount = TASK_COUNT;

this.worker_num = worker_num;

taskQueue = new ArrayBlockingQueue<>(taskCount);

workThreads = new WorkThread[worker_num];

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

workThreads[i] = new WorkThread();

workThreads[i].start();

}

}

// 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器决定

public void execute(Runnable task) {

try {

taskQueue.put(task);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

// 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁

public void destroy() {

// 工作线程停止工作,且置为null

System.out.println(“ready close pool…”);

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

workThreads[i].stopWorker();

workThreads[i] = null;//help gc

}

taskQueue.clear();// 清空任务队列

}

// 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数

@Override

public String toString() {

return “WorkThread number:” + worker_num

  • " wait task number:" + taskQueue.size();

}

/**

  • 内部类,工作线程

*/

private class WorkThread extends Thread{

@Override

public void run(){

Runnable r = null;

try {

while (!isInterrupted()) {

//监听阻塞队列,如果有任务,则执行相应的任务

r = taskQueue.take();

if(r!=null) {

System.out.println(getId()+" ready exec :"+r);

r.run();

}

r = null;//help gc;

}

} catch (Exception e) {

// TODO: handle exception

}

}

//停止线程

public void stopWorker() {

interrupt();

}

}

}

该线程池中,我们创建了workThreads用来保存运行的线程,使用BlockingQueue taskQueue用来保存我们的任务队列。

===============================================================================

1、定义WorkThread类,用来表示执行的线程,用于监听阻塞队列任务。

2、创建构建函数,我们将线程池进行初始化,并启动所有的工作线程。workThreads用来保存运行的线程,使用BlockingQueue taskQueue用来保存我们的任务队列

3、创建提交任务方法execute,用于提交我们的任务。

4、创建销毁线程池的方法destroy,用于销毁线程池。

之后我们编写测试类

import java.util.Random;

/**

  • @Auther: BlackKingW

  • @Date: 2019/4/14 12:09

  • @Description:

*/

public class TestMyThreadPool {

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

// 创建3个线程的线程池

MyThreadPool t = new MyThreadPool(3,0);

t.execute(new MyTask(“testA”));

t.execute(new MyTask(“testB”));

t.execute(new MyTask(“testC”));

t.execute(new MyTask(“testD”));

t.execute(new MyTask(“testE”));

System.out.println(t);

Thread.sleep(10000);

t.destroy();// 所有线程都执行完成才destory

System.out.println(t);

}

// 任务类

static class MyTask implements Runnable {

private String name;

private Random r = new Random();

public MyTask(Str

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

ing name) {

this.name = name;

}

public String getName() {

return name;

}

@Override

public void run() {// 执行任务

try {

Thread.sleep(r.nextInt(1000)+2000);

} catch (InterruptedException e) {

System.out.println(Thread.currentThread().getId()+" sleep InterruptedException:"

+Thread.currentThread().isInterrupted());

}

System.out.println(“任务 " + name + " 完成”);

}

}

}

=====================================================================================================================================

能按照线程池的方式进行执行。

我们简单地手动写了一个线程池,但以上线程池有哪些问题呢?

1、启动的时候就将所有线程启动了,如果长时间不用比较消耗资源。

2、没有任务饱和的一个错略。

3、没有任务超时机制等等。

三、JDK中的线程池和工作机制

===============

我们大致了解了线程池的一个机制,那我们看下JDK中,是如何实现线程池的吧。

1、线程池的创建

JAVA中,ThreadPoolExecutor,是所有线程池实现的父类,类结构图如下。

它的构造函数含有以下参数

参数含义
int corePoolSize 线程池中核心线程数,< corePoolSize  ,就会创建新线程,= corePoolSize  ,这个任务就会保存到BlockingQueue,如果调用prestartAllCoreThreads()方法就会一次性的启动corePoolSize  个数的线程。
int maximumPoolSize允许的最大线程数,如果BlockingQueue也满了,并且线程数< maximumPoolSize时候就会再次创建新的线程
long keepAliveTime线程空闲下来后,存活的时间,这个参数只在线程数> corePoolSize才有用
TimeUnit unit存活时间的单位值
BlockingQueue<Runnable> workQueue保存任务的阻塞队列
ThreadFactory threadFactory创建线程的工厂,给新建的线程赋予名字
RejectedExecutionHandler handler

饱和策略

AbortPolicy :直接抛出异常,默认;

CallerRunsPolicy:用调用者所在的线程来执行任务

DiscardOldestPolicy:丢弃阻塞队列里最老的任务,队列里最靠前的任务

DiscardPolicy :当前任务直接丢弃

实现自己的饱和策略只要实现RejectedExecutionHandler接口即可

提交任务

execute(Runnable command)  不需要返回

Future submit(Callable task) 需要返回值

关闭线程池

shutdown(),shutdownNow();

shutdownNow():设置线程池的状态,还会尝试停止正在运行或者暂停任务的线程

shutdown()设置线程池的状态,只会中断所有没有执行任务的线程

2、线程池的工作机制

1、如果工作线程数小于核心线程数,则创建工作线程

2、如果工作线程数等于或者大于核心线程数,则将任务提交到阻塞队列中

3、如果阻塞队列也满了,但线程数小于最大线程数,则创建新的线程

4、如果创建新的线程也满了,则执行任务饱和策略。

源码如下

3、如何合理配置线程池

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值