java 线程中途返回一个值,java线程池的使用

线程池的使用

标签(空格分隔): 多线程

Executors工具类(创建池与提交任务)

通过工具类,可以创建线程池

常见的几种线程池创建

通过Executors的静态方法创建线程池

1.创建固定大小的线程池(可用于服务器瞬时削峰、限流,但需注意长时间持续高峰情况造成的队列阻塞)

ExecutorService executorService = Executors.newFixedThreadPool(int n);//n是线程池大小

2.创建可变大小的线程池(适用场景:快速处理大量耗时较短的任务)

ExecutorService executorService = Executors.newCachedThreadPool()

3.创建单线程的线程池(因为只有一个线程,所以提交的任务都是串行执行,可以解决并发执行带来的同步问题)

ExecutorService executorService = Executors.newSingleThreadExecutor()

ps:这个线程池,只会创建一次线程,用这个线程来执行所有提交过来的任务,并不是每来一次任务创建一次

4.创建一个可定期或者延时执行任务的定长线程池,支持定时及周期性任务执行

ScheduledExecutorService executors.newScheduledThreadPool()

延迟3秒钟后执行任务

scheduledThreadPool.schedule(new Runnable() {

@Override

public void run() {

System.out.println("运行时间: " + sdf.format(new Date()));

}

}, 3, TimeUnit.SECONDS);

延迟1秒钟后每隔3秒执行一次任务

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

@Override

public void run() {

System.out.println("运行时间: " + sdf.format(new Date()));

}

}, 1, 3, TimeUnit.SECONDS);

5.创建一个具有抢占式操作的线程池(JDK1.8新增,适合使用在很耗时的操作)

newWorkStealingPool适合使用在很耗时的操作

ExecutorService executorService = Executors.newWorkStealingPool();

WorkStealingPool

工作窃取线程池

假设共有三个线程同时执行, A, B, C

当A,B线程池尚未处理任务结束,而C已经处理完毕,则C线程会从A或者B中窃取任务执行,这就叫工作窃取

假如A线程中的队列里面分配了5个任务,而B线程的队列中分配了1个任务,当B线程执行完任务后,它会主动的去A线程中窃取其他的任务进行执行WorkStealingPool 背后是使用 ForkJoinPool实现的

public class T11_WorkStealingPool {

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

// CPU 核数

System.out.println(Runtime.getRuntime().availableProcessors());

// workStealingPool 会自动启动cpu核数个线程去执行任务

ExecutorService service = Executors.newWorkStealingPool();

service.execute(new R(10000)); // 我的cpu核数为12 启动13个线程,其中第一个是1s执行完毕,其余都是2s执行完毕,

// 有一个任务会进行等待,当第一个执行完毕后,会再次偷取第十三个任务执行

for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {

service.execute(new R(2000));

}

// 因为work stealing 是deamon线程,即后台线程,精灵线程,守护线程

// 所以当main方法结束时, 此方法虽然还在后台运行,但是无输出

// 可以通过对主线程阻塞解决

System.in.read();

}

static class R implements Runnable {

int time;

R(int time) {

this.time = time;

}

@Override

public void run() {

try {

TimeUnit.MILLISECONDS.sleep(time);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(Thread.currentThread().getName() + " " + time);

}

}

}

通过ExecutorService实例提交任务

a.通过sumbit提交任务,带Future返回值,任务类型可以为Runable和Callable型

1. 当任务类型为Runnable型的时候

Future future = executorService.submit(runnable)

执行执行完毕后,返回null,future.get(),将阻塞主线程,获取null值

2. 当任务类型为Callable型的时候

Future future = executorService.submit(callable)

任务执行完毕后,返回执行结果,执行结果类型与Callable泛型一致,future.get()阻塞主线程,并获取返回值

b.通过execute提交任务,没有返回值,任务类型只能是Runable类型

executorService. (runnable)

ThreadPoolExecutor创建方式

ThreadPoolExecutor提供了四个构造方法,提供不同的参数类型

1 corePoolSize int 核心线程池大小

2 maximumPoolSize int 最大线程池大小

3 keepAliveTime long 线程最大空闲时间

4 unit TimeUnit 时间单位

5 workQueue BlockingQueue<Runnable> 线程等待队列

6 threadFactory ThreadFactory 线程创建工厂

7 handler RejectedExecutionHandler 拒绝策略。

线程池的关闭

在大多数人开发过程中,大家关注的是如何创建、使用线程池,但很少有人去关系线程池的关闭,甚至忘记调用shutdown()方法,这可能导致内存溢出。

注意:FixedThreadPool的核心线程不会自动超时关闭,必须要手动的调用shutdown关闭线程池,不然会导致内存溢出。

线程池自动关闭的两个条件:

1.线程池的引用不可达

2.线程池中没有线程;

两个关闭方法差异

1.shutdown()

线程池虽然关闭,但是队列中已有的任务仍然会继续执行

2.shutdownNow()

强制关闭线程池,线程的任务队列里的线程将不会被执行,而正在被执行的线程也会中断(可以在interrupted中处理)

正确的关闭线程池,需要考虑以下3个问题

1.如何拒绝新来的请求任务

2.如何处理线程池等待队列里的任务

3.如何处理正在执行的任务

线程池的拒绝策略

默认的拒绝策略

ThreadPoolExecutor源码中可以看到以下内容

private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();

线程池的默认拒绝策略为AbortPolicy,即丢弃任务并抛出RejectedExecutionException异常

1.AbortPolicy(默认,丢弃并抛异常)

ThreadPoolExecutor.AbortPolicy

丢弃任务并抛出RejectedExecutionException异常。

这是线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。

2.DiscardPolicy(静默丢弃,不会给出任何异常提示)

ThreadPoolExecutor.DiscardPolicy

建议是一些无关紧要的业务采用此策略

3.DiscardOldestPolicy(喜新厌旧的拒绝策略)

ThreadPoolExecutor.DiscardOldestPolicy

它会丢掉队列最前面的任务,然后接收新来的任务,典型的是一种喜新厌旧的策略方式

4.CallerRunsPolicy(我干不了,你自己干吧)

ThreadPoolExecutor.CallerRunsPolicy由调用线程处理该任务

你提交给我,但是我没时间干呀,你自己干吧。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值