当前位置: 首页 > news >正文

Java多线程(三)——线程池及定时器

线程池就是一个可以复用线程的技术。前面三种多线程方法就是在用户发起一个线程请求就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。线程池就相当于预先创建好几个线程(招聘几个打工人),来分配之后要处理的任务(干活)

线程池的接口:ExecutorService

线程池对象

  1. 使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象

可以看到有7个参数,通过这些参数设置线程池的规模和特征。ExecutorService的常用方法有execute、submit、shutdown、shutdownNow。

  1. ThreadPoolExecutor构造器的参数:

  1. 1:指定线程池的线程数量(核心线程): corePoolSize

  1. 2:指定线程池可支持的最大线程数: maximumPoolSize

  1. 3:指定临时线程的最大存活时间: keepAliveTime

  1. 4:指定存活时间的单位(秒、分、时、天): unit

  1. 5:指定任务队列: workQueue

  1. 6:指定用哪个线程工厂创建线程: threadFactory

  1. 7:指定线程忙,任务满的时候,新任务来了怎么办: handler,默认丢弃任务并抛出RejectedExecutionException异常。

  1. ThreadPoolExecutor创建线程池对象

ExecutorService pool=new ThreadPoolExecutor(3,6,8, TimeUnit.SECONDS,new ArrayBlockingQueue<>(6), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
  1. 线程池处理Runnable任务 ——pool.execute()

首先实现Runnable接口,重写run方法。然后创建MyRunnable任务对象,只不过这里不是把MyRunnable任务对象交给Thread处理,而是使用线程池pool的execute()方法。

class myRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + " ——>" + i);}try {System.out.println(Thread.currentThread().getName() + " —— 休眠");Thread.sleep(2000);System.out.println(Thread.currentThread().getName() + " —— 启动");} catch (InterruptedException e) {e.printStackTrace();}}
}
//Runnable target=new myRunnable();pool.execute(target);
  1. 线程池处理Callable任务 ——pool.submit()

定义类实现Callable接口,重写call方法,封装要做的事情。然后把Callable对象进行submit(),并且可以返回执行后的结果。

class myCallable implements Callable<String> {private int n;public myCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {int s=0;for (int i = 0; i < n; i++) {s+=n;}return Thread.currentThread().getName()+" 1+...+" + n +", 子线程执行结果: "+s;}
}
//Callable myCallable=new myCallable(10);Future<String> f1 = pool.submit(myCallable);System.out.println(f1.get());
  1. 使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象

Executors的底层其实也是基于线程池的实现类ThreadPoolExecutor创建线程池对象的。Executors得到线程池对象的常用方法:

方法

说明

弊端

public static ExecutorService newCachedThreadPool()

线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉。

允许创建的线程数量最大上限是Integer.MAX_VALUE,非常非常大

可能会创建大量线程,出现OOM错误( 内存溢出 java.lang.OutOfMemoryError )

public static ExecutorService newFixedThreadPool(int nThreads)

创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。

允许请求的任务队列长度是Integer.MAX_VALUE,可能会堆积大量请求,出现OOM错误

public static ExecutorService newSingleThreadExecutor ()

创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。

允许请求的任务队列长度是Integer.MAX_VALUE,可能会堆积大量请求,出现OOM错误

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。

允许创建的线程数量最大上限是Integer.MAX_VALUE,

可能会创建大量线程,出现OOM错误

Executors不适合做大型互联网场景的线程池方案,建议使用ThreadPoolExecutor来指定线程池参数,这样可以明确线程池的运行规则,规避资源耗尽的风险。

  1. 定时器

定时器是一种控制任务延时调用,或者周期调用的技术。定时器的实现方式有两种:

方式一:Timer。创建Timer定时器对象,然后开启定时器。这是一种单线程方法,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入。可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行。

    Timer t=new Timer();t.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("定时器~");}},3000,3000);

方式二: ScheduledExecutorService定时器。基于线程池,某个任务的执行情况不会影响其他定时任务的执行。先得到线程池对象,然后再进行周期调度方法。

        ScheduledExecutorService pool=Executors.newScheduledThreadPool(3);pool.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {System.out.println("定时器");}},3,3,TimeUnit.SECONDS);
  1. 并发与并行

CPU同时可以处理线程的数量有限,所以CPU会轮询为每个线程服务,只是由于CPU切换的速度很快,给我们的感觉这些线程在同时执行,其实可能只是并发。所以说多个线程其实是并发与并行同时进行的

  1. 线程的6种状态

NEW(新建)

线程刚被创建,但是并未启动。

Runnable(可运行)

线程已经调用了start()等待CPU调度。

Blocked(锁阻塞)

线程在执行的时候未竞争到锁对象,则该线程进入Blocked状态。

Waiting(无限等待)

一个线程进入Waiting状态,另一个线程调用notify或者notifyAll方法才能够唤醒。

Timed Waiting(计时等待)

同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。带有超时参数的常用方法有Thread.sleep 、Object.wait。

Teminated(被终止)

因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。

http://www.lryc.cn/news/27860.html

相关文章:

  • Linux命令行安装Oracle19c教程和踩坑经验
  • Linux常用命令等
  • CEC2014:鱼鹰优化算法(Osprey optimization algorithm,OOA)求解CEC2014(提供MATLAB代码
  • MyBatis底层原理【源码运行时序图】
  • k8s 系列之 CoreDNS 解读
  • 从测试鸡蛋硬度到跳表的设计
  • 3D立体视觉成像原理介绍【一 】
  • CEC2021:鱼鹰优化算法(Osprey optimization algorithm,OOA)求解CEC2021(提供MATLAB代码
  • 0301_对应的南京比特物联网
  • 钡铼技术BL302 ARM工控机QT图形化界面开发的实践
  • Python try except异常处理详解(入门必读)
  • 信息系统基本知识(三)软件工程
  • Linux下软件部署安装管理----rpmbuild打包rpm包部署安装
  • ThreadLocal学会了这些,你也能和面试官扯皮了!
  • 【存储】存储特性
  • Qt使用OpenGL进行多线程离屏渲染
  • Vue基础入门讲义(三)-指令
  • pod资源限制,探针(健康检查)
  • Python | 蓝桥杯进阶第一卷——字符串
  • 2023-03-03 mysql列存储-cpu占用100%-追踪思路
  • JVM—类加载子系统
  • 在codeIgniter3中session.php中的数组追加值
  • Windows环境下Gpu版本的Pytorch安装
  • 项目实战典型案例13——学情页面逻辑问题
  • 工作日志day02
  • C++Primer16.1.6节练习
  • 初尝并行编程
  • keepalived学习记录:对其vip漂移过程采用gdb跟踪
  • 51单片机串口通讯原理及程序源码-----day8
  • mongodb入门到使用(下)