在java中,如果要实现多线程,就必须依靠线程主体类,而java.lang.Thread是java中负责多线程操作类,只需继承Thread类,就能成为线程主体类,为满足一些特殊要求,也可以通过实现Runnable接口或者Callable接口来完成定义。
具体方式如下:
1.继承Thread类,重写run方法(无返回值)
2.实现Runnable接口,重写run方法(无返回值)
3.实现Callable接口,重写call方法(有返回值且可以抛出异常) 重点:注意多线程操作数据的一致性,悲观锁和乐观锁的使用。
配置参数:
corePoolSize:线程池维护线程的最小数量。
maximumPoolSize:线程池维护线程的最大数量。
keepAliveTime:空闲线程的存活时间。
TimeUnit unit:时间单位,现有纳秒,微秒,毫秒,秒枚举值。
BlockingQueue workQueue:持有等待执行的任务队列。
RejectedExecutionHandler handler:用来拒绝一个任务的执行,有两种情况会发生这种情况。
一是在execute方法中若addIfUnderMaximumPoolSize(command)为false,即线程池已经饱和;
二是在execute方法中, 发现runState!=RUNNING || poolSize == 0,即已经shutdown,就调用ensureQueuedTaskHandled(Runnable command),在该方法中有可能调用reject。
ThreadPoolExecutor池子的处理流程如下:
当池子大小小于corePoolSize就新建线程,并处理请求。
当池子大小等于corePoolSize,把请求放入workQueue中,池子里的空闲线程就去从workQueue中取任务并处理。
当workQueue放不下新入的任务时,新建线程入池,并处理请求,如果池子大小撑到了maximumPoolSize就用RejectedExecutionHandler来做拒绝处理。
另外,当池子的线程数大于corePoolSize的时候,多余的线程会等待keepAliveTime长的时间,如果无请求可处理就自行销毁。
其会优先创建 CorePoolSize 线程, 当继续增加线程时,先放入Queue中,当 CorePoolSiz 和 Queue 都满的时候,就增加创建新线程,当线程达到MaxPoolSize的时候,就会抛出错 误 org.springframework.core.task.TaskRejectedException
另外MaxPoolSize的设定如果比系统支持的线程数还要大时,会抛出java.lang.OutOfMemoryError: unable to create new native thread 异常。
Reject策略预定义有四种:
ThreadPoolExecutor.AbortPolicy策略,是默认的策略,处理程序遭到拒绝将抛出运行时 RejectedExecutionException。
ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃。
ThreadPoolExecutor.DiscardPolicy策略,不能执行的任务将被丢弃。
ThreadPoolExecutor.DiscardOldestPolicy策略,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。
spring的包装了一下jdk,其实底层都是jdk的线程池。
Spring的线程池是为spring自己使用线程的部件而写的。 使得spring组件不依赖Java的并行库而只依赖自己简化的线程相关的封装。
进程:进程是指在系统中正在运行的一个应用程序,程序一旦运行就是进程。
特点:
1、每个进程可以包括多个线程
2、每个进程都有自己独立的内存空间