Callable 创建线程
- 实现Callable接口 ,重写call方法。
- 该线程不能够直接自己启动,需要使用线程池来启动。启动之后会调用call方法进行具体的操作。
- Call方法可以有返回值 。
- 启动线程的方式:start 方法和使用线程池启动 。
一.run方法和call的区别 ?
run属于runnable线程的,没有返回值.
call属于callable线程的,可以有返回值.
二.线程池
-
在之前的线程操作中,每一次创建线程对象-----启动执行线程----销毁。如果有大量的线程对象的创建和销毁操作,对内存的消耗是非常大的。
-
池的概念: 创建一个池 ,里面提前放入一定数量的线程对象,要使用的话就从线程池中去取一个线程对象,如果当前线程池的线程被用完了,其余人需要等待线程换回到线程池中才可以继续使用。
-
在程序启动的时候相对较慢,因为它要创建需要的多个线程对象 。优点是不需要重复的进行线程对象的创建,节省重复创建对象的操作。
-
线程池的优势: 可以重复进行线程的使用,避免重复的创建和销毁线程
1.线城池的操作步骤:
- 创建线程池
- 创建线程对象,将线程放到线程池中
- 从线程池中获取线程对象进行使用
2. 线程池的种类
- ThreadPoolExecutor: 使用的是该类来进行线程池的创建和操作.
- ThreadPoolExecutor 固定(任务计划),用ScheduledThreadPoolExecutor 来做。
可以创建四种类型的线程池 :
FixedThreadPool 线程数固定的线程池,程序开始的时候会比较慢,线程数量是固定的。
SingleThreadExecutor线程数量为1的线程池,唯一的线程,不能处理并发,只有一个线程。
CachedThreadPool缓存有关的线程池,如果线程池中原本有三个线程,但是有四个对象要使用线程,此时会在创建一个新的线程对象 ;随意扩展。
ScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行,固定长度 定时执行 。
3.创建线程池(使用 Executors来创建)
- ExecutorService线程池业务类来进行操作.
- Executor是用来操作线程池中的线程的.
3.1Executors
3.1.1常用方法
返回值 | 方法 | 含义 |
---|---|---|
static Callable | callable(PrivilegedAction action) | 返回 Callable 对象,调用它时可运行给定特权的操作并返回其结果。 |
static Callable | callable(PrivilegedExceptionAction action) | 返回 Callable 对象,调用它时可运行给定特权的异常操作并返回其结果。 |
static Callable | callable(Runnable task) | 返回 Callable 对象,调用它时可运行给定的任务并返回 null。 |
static Callable | callable(Runnable task, T result) | 返回 Callable 对象,调用它时可运行给定的任务并返回给定的结果。 |
static ThreadFactory | defaultThreadFactory() | 返回用于创建新线程的默认线程工厂。 |
static ExecutorService | newCachedThreadPool() | 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。 |
static ExecutorService | newCachedThreadPool(ThreadFactory threadFactory) | 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程。 |
static ExecutorService | newFixedThreadPool(int nThreads) | 创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。 |
static ExecutorService | newFixedThreadPool(int nThreads, ThreadFactory threadFactory) | 创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。 |
static ScheduledExecutorService | newScheduledThreadPool(int corePoolSize) | 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 |
static ScheduledExecutorService | newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) | 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。 |
static ExecutorService | newSingleThreadExecutor() | 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 |
static ExecutorService | newSingleThreadExecutor(ThreadFactory threadFactory) | 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程,并在需要时使用提供的 ThreadFactory 创建新线程。 |
static ScheduledExecutorService | newSingleThreadScheduledExecutor() | 创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 |
static ScheduledExecutorService | newSingleThreadScheduledExecutor(ThreadFactory threadFactory) | 创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 |
static Callable | privilegedCallable(Callable callable) | 返回 Callable 对象,调用它时可在当前的访问控制上下文中执行给定的 callable 对象。 |
static Callable | privilegedCallableUsingCurrentClassLoader(Callable callable) | 返回 Callable 对象,调用它时可在当前的访问控制上下文中,使用当前上下文类加载器作为上下文类加载器来执行给定的 callable 对象。 |
static ThreadFactory | privilegedThreadFactory() | 返回用于创建新线程的线程工厂,这些新线程与当前线程具有相同的权限。 |
3.2Executor
返回值 | 方法 | 含义 | 注释 |
---|---|---|---|
void | execute(Runnable command) | 在未来某个时间执行给定的命令。 | command - 可运行的任务 |
3.3 ExecutorService线程池的业务类
3.3.1常用方法
返回值 | 方法 | 含义 |
---|---|---|
boolean | awaitTermination(long timeout, TimeUnit unit) | 请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。 |
List<Future> | invokeAll(Collection<Callable> tasks) | 执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。 |
List<Future> | invokeAll(Collection<Callable> tasks, long timeout, TimeUnit unit) | 执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。 |
T | invokeAny(Collection<Callable> tasks) | 执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。 |
T | invokeAny(Collection<Callable> tasks, long timeout, TimeUnit unit) | 执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。 |
boolean | isShutdown() | 如果此执行程序已关闭,则返回 true。 |
boolean | isTerminated() | 如果关闭后所有任务都已完成,则返回 true。 |
void | shutdown() | 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。 |
List | shutdownNow() | 试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。 |
Future | submit(Callable task) | 提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。 |
Future<?> | submit(Runnable task) | 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。 |
Future | submit(Runnable task, T result) | 提交一个 Runnable 任务用于执行,并返回一个 Future,该 Future 表示任务一旦完成后即返回给定的结果。 |
创建线程池
@Test
void pool() {
//创建线程池
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);//创建定长的线程池
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();//创建可变长度的线程池
ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();//创建只有一个的线程池,单一线程池对象
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(3);//创建定长的线程池
//实例化,ThreadPoolExecutor线程池对象,在实例化的时候可以设置参数
//ThreadPoolExecutor threadpool=new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
3.4Future类常用方法
返回值 | 方法 | 含义 |
---|---|---|
boolean | cancel(boolean mayInterruptIfRunning) | 试图取消对此任务的执行。 |
V | get() | 如有必要,等待计算完成,然后检索其结果。 |
V | get(long timeout, TimeUnit unit) | 如有必要,最多等待为使计算完成所给定的时间之后,检索其结果(如果结果可用)。 |
boolean | isCancelled() | 如果在任务正常完成前将其取消,则返回 true。 |
boolean | isDone() | 如果任务已完成,则返回 true。 |
启动执行线程
//使用线程池来做
@Test
void pool02() {
//两个线程池
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);//创建定长的线程池
//execute:只能对runnable和thread线程操作
//submit:runnable和callable都可以
RunnableDemo runnableThread=new RunnableDemo();
Thread th=new Thread(runnableThread,"线程一");
//启动传入的线程对象
//newFixedThreadPool.execute(th);/newFixedThreadPool.execute(runnableThread);
//启动线程,可以不要返回值
newFixedThreadPool.submit(runnableThread);//==Future<?> submit2 = newFixedThreadPool.submit(runnableThread);
//callable线程
CallableThread callableThread=new CallableThread();
//submit会调用callable的call方法,将返回值保存到Futurn中
Future<Integer> submit = newFixedThreadPool.submit(callableThread);
try {
System.out.println("callable的call方法的返回值是"+submit.get());
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//使用线程池来做
@Test
void pool03() {
//两个线程池
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(2);//创建定长的线程池
//execute:只能对runnable和thread线程操作
//submit:runnable和callable都可以
//第一个线程
RunnableDemo runnabledemo=new RunnableDemo();
//启动线程,可以不要返回值
newFixedThreadPool.submit(runnabledemo);//==Future<?> submit2 = newFixedThreadPool.submit(runnableThread);
//callable线程,第二个线程
CallableThread callableThread=new CallableThread();
//submit会调用callable的call方法,将返回值保存到Futurn中
Future<Integer> submit = newFixedThreadPool.submit(callableThread);
//使用第三个线程
RunnableDemo runnableThread01=new RunnableDemo();
newFixedThreadPool.submit(runnableThread01);
newFixedThreadPool.shutdown();
newFixedThreadPool.shutdownNow();
}
execute和submit的区别:
- execute:只能对runnable和thread线程操作
- submit:runnable和callable都可以
4.ThreadPoolExecutor线程池
- Executor 操作类Executors
- ExecutorService具体的操作类
- AbstractExecutorService
- ThreadPoolExecutor
- ScheduledThreadPoolExecutor
4.1构造方法
构造方法 | 含义 |
---|---|
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) | 用给定的初始参数和默认的线程工厂及处理程序创建新的 ThreadPoolExecutor。 |
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, RejectedExecutionHandler handler) | 用给定的初始参数创建新的 ThreadPoolExecutor。 |
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory) | 用给定的初始参数创建新的 ThreadPoolExecutor。 |
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) | 用给定的初始参数创建新的 ThreadPoolExecutor。 |
参数含义:
- corePoolSize - 池中所保存的线程数,包括空闲线程。
- maximumPoolSize - 池中允许的最大线程数。
- keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
- unit - keepAliveTime 参数的时间单位。
- workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute 方法提交的 Runnable 任务。
- threadFactory - 执行程序创建新线程时使用的工厂。
- handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
4.2通过ThreadPoolExecutor来了解线程池参数该线程池是定长的
-
从源码中可以看出,线程池的构造函数有7个参数,分别是corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。下面会对这7个参数一一解释。
(1)corePoolSize 线程池核心线程大小
线程池中会维护一个最小的线程数量,即使这些线程处理空闲状态,他们也不会 被销毁,除非设置了allowCoreThreadTimeOut。这里的最小线程数量即是corePoolSize。
(2)maximumPoolSize 线程池最大线程数量
一个任务被提交到线程池以后,首先会找有没有空闲存活线程,如果有则直接执行,如果没有则会缓存到工作队列中,如果工作队列满了,才会创建一个新线程,然后从工作队列的头部取出一个任务交由新线程来处理,而将刚提交的任务放入工作队列尾部。线程池不会无限制的去创建新线程,它会有一个最大线程数量的限制,这个数量即由maximunPoolSize指定。
(3)keepAliveTime 空闲线程存活时间
一个线程如果处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁,这里的指定时间由keepAliveTime来设定
(4)unit 空闲线程存活时间单位
keepAliveTime的计量单位
(5)workQueue 工作队列
新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。jdk中提供了四种工作队列: -
ArrayBlockingQueue
基于数组的有界阻塞队列,按FIFO先进先出排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。 -
LinkedBlockingQuene
基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。 -
SynchronousQuene
一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。 -
PriorityBlockingQueue
具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
(6)threadFactory 线程工厂
创建一个新线程时使用的工厂,可以用来设定线程名、是否为daemon线程等等
(7)handler 拒绝策略
当工作队列中的任务已到达最大限制,并且线程池中的线程数量也达到最大限制,这时如果有新任务提交进来,该如何处理呢。这里的拒绝策略,就是解决这个问题的,jdk中提供了4中拒绝策略: -
CallerRunsPolicy
该策略下,在调用者线程中直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务。
-
AbortPolicy
该策略下,直接丢弃任务,并抛出RejectedExecutionException异常。
-
DiscardPolicy
该策略下,直接丢弃任务,什么都不做。
-
DiscardOldestPolicy
该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列
4.3常用方法
返回值 | 方法 | 含义 |
---|---|---|
protected void | afterExecute(Runnable r, Throwable t) | 基于完成执行给定 Runnable 所调用的方法。 |
boolean | awaitTermination(long timeout, TimeUnit unit) | 请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。 |
protected void | beforeExecute(Thread t, Runnable r) | 在执行给定线程中的给定 Runnable 之前调用的方法。 |
void | execute(Runnable command) | 在将来某个时间执行给定任务。 |
protected void | finalize() | 当不再引用此执行程序时,调用 shutdown。 |
int | getActiveCount() | 返回主动执行任务的近似线程数。 |
int | getCompletedTaskCount() | 返回已完成执行的近似任务总数。 |
long | getCorePoolSize() | 返回核心线程数。 |
long | getKeepAliveTime(TimeUnit unit) | 返回线程保持活动的时间,该时间就是超过核心池大小的线程可以在终止前保持空闲的时间值。 |
int | getLargestPoolSize() | 返回曾经同时位于池中的最大线程数。 |
int | getMaximumPoolSize() | 返回允许的最大线程数。 |
int | getPoolSize() | 返回池中的当前线程数。 |
BlockingQueue | getQueue() | 返回此执行程序使用的任务队列。 |
RejectedExecutionHandler | getRejectedExecutionHandler() | 返回用于未执行任务的当前处理程序。 |
long | getTaskCount() | 返回计划执行的近似任务总数。 |
ThreadFactory | getThreadFactory() | 返回用于创建新线程的线程工厂。 |
boolean | isShutdown() | 如果此执行程序已关闭,则返回 true。 |
boolean | isTerminated() | 如果关闭后所有任务都已完成,则返回 true。 |
boolean | isTerminating() | 如果此执行程序处于在 shutdown 或 shutdownNow 之后正在终止但尚未完全终止的过程中,则返回 true。 |
int | prestartAllCoreThreads() | 启动所有核心线程,使其处于等待工作的空闲状态。 |
boolean | prestartCoreThread() | 启动核心线程,使其处于等待工作的空闲状态。 |
void | purge() | 试图从工作队列移除所有已取消的 Future 任务。 |
boolean | remove(Runnable task) | 从执行程序的内部队列中移除此任务(如果出现),这样如果尚未开始,则其不再运行。 |
void | setCorePoolSize(int corePoolSize) | 设置核心线程数。 |
void | setKeepAliveTime(long time, TimeUnit unit) | 设置线程在终止前可以保持空闲的时间限制。 |
void | setMaximumPoolSize(int maximumPoolSize) | 设置允许的最大线程数。 |
void | setRejectedExecutionHandler(RejectedExecutionHandler handler) | 设置用于未执行任务的新处理程序。 |
void | setThreadFactory(ThreadFactory threadFactory) | 设置用于创建新线程的线程工厂。 |
void | shutdown() | 按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。 |
List | shutdownNow() | 尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。 |
protected void | terminated() | 当 Executor 已经终止时调用的方法。 |
- RunnableTh.java
public class RunnableTh implements Runnable{
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"线程池在启动线程");
}
}
- ThreadPool.java
public class ThreadPool {
public static void main(String[] args) {
//创建线程池对象
/*
* corePoolSize 核心线程
* maximumPoolSize 最大线程数量
* 大部分是 核心线程 ==最大线程数量
* keepAliveTime 空闲线程最长存活时间
* unit 单位
* workQueue 队列形式
*/
ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(2, 3, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2));
//调用线程
RunnableTh runnableTh01=new RunnableTh();
Thread t01=new Thread(runnableTh01,"num01");
Thread t02=new Thread(runnableTh01,"num01");
Thread t03=new Thread(runnableTh01,"num01");
t01.start();//用完会自动销毁
//执行
boolean remove = threadPoolExecutor.remove(t02);
System.out.println(remove);
threadPoolExecutor.execute(t01);
//true线程使用完将线程关闭
//false线程使用完线程不闭
threadPoolExecutor.allowCoreThreadTimeOut(true);
threadPoolExecutor.execute(t02);
threadPoolExecutor.submit(t03);
//程序执行完,但是线程池没有关闭
//停止掉所有的线程
threadPoolExecutor.shutdown();
//获取线程池的信息
System.out.println("核心线程数量"+threadPoolExecutor.getCorePoolSize());
System.out.println("总线程数量"+threadPoolExecutor.getMaximumPoolSize());
//现有数量小于等于核心线程数量
System.out.println("现有的线程数量"+threadPoolExecutor.getPoolSize());
BlockingQueue<Runnable> queue = threadPoolExecutor.getQueue();
System.out.println("队列形式"+queue);
}
}
- 定时打开一个任务
public class SchPool {
public static void main(String[] args) {
//创建线程池
ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(3);
//要执行的线程,间隔时间,时间单位
scheduledThreadPoolExecutor.schedule(new OpenExe(), 10, TimeUnit.SECONDS);
System.out.println("等待");
}
}
class OpenExe implements Runnable{
@Override
public void run() {
try {
Runtime.getRuntime().exec("C:\\Program Files (x86)\\Netease\\CloudMusic\\cloudmusic.exe");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
}
}