多线程的基本使用02(线程池)

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 Callablecallable(PrivilegedAction action)返回 Callable 对象,调用它时可运行给定特权的操作并返回其结果。
static Callablecallable(PrivilegedExceptionAction action)返回 Callable 对象,调用它时可运行给定特权的异常操作并返回其结果。
static Callablecallable(Runnable task)返回 Callable 对象,调用它时可运行给定的任务并返回 null。
static Callablecallable(Runnable task, T result)返回 Callable 对象,调用它时可运行给定的任务并返回给定的结果。
static ThreadFactorydefaultThreadFactory()返回用于创建新线程的默认线程工厂。
static ExecutorServicenewCachedThreadPool()创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
static ExecutorServicenewCachedThreadPool(ThreadFactory threadFactory)创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程。
static ExecutorServicenewFixedThreadPool(int nThreads)创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。
static ExecutorServicenewFixedThreadPool(int nThreads, ThreadFactory threadFactory)创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。
static ScheduledExecutorServicenewScheduledThreadPool(int corePoolSize)创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
static ScheduledExecutorServicenewScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
static ExecutorServicenewSingleThreadExecutor()创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
static ExecutorServicenewSingleThreadExecutor(ThreadFactory threadFactory)创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程,并在需要时使用提供的 ThreadFactory 创建新线程。
static ScheduledExecutorServicenewSingleThreadScheduledExecutor()创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
static ScheduledExecutorServicenewSingleThreadScheduledExecutor(ThreadFactory threadFactory)创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
static CallableprivilegedCallable(Callable callable)返回 Callable 对象,调用它时可在当前的访问控制上下文中执行给定的 callable 对象。
static CallableprivilegedCallableUsingCurrentClassLoader(Callable callable)返回 Callable 对象,调用它时可在当前的访问控制上下文中,使用当前上下文类加载器作为上下文类加载器来执行给定的 callable 对象。
static ThreadFactoryprivilegedThreadFactory()返回用于创建新线程的线程工厂,这些新线程与当前线程具有相同的权限。

3.2Executor

返回值方法含义注释
voidexecute(Runnable command)在未来某个时间执行给定的命令。command - 可运行的任务

3.3 ExecutorService线程池的业务类

3.3.1常用方法
返回值方法含义
booleanawaitTermination(long timeout, TimeUnit unit)请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
List<Future>invokeAll(Collection<Callable> tasks)执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。
List<Future>invokeAll(Collection<Callable> tasks, long timeout, TimeUnit unit)执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
TinvokeAny(Collection<Callable> tasks)执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
TinvokeAny(Collection<Callable> tasks, long timeout, TimeUnit unit)执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。
booleanisShutdown()如果此执行程序已关闭,则返回 true。
booleanisTerminated()如果关闭后所有任务都已完成,则返回 true。
voidshutdown()启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
ListshutdownNow()试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
Futuresubmit(Callable task)提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
Future<?>submit(Runnable task)提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
Futuresubmit(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类常用方法

返回值方法含义
booleancancel(boolean mayInterruptIfRunning)试图取消对此任务的执行。
Vget()如有必要,等待计算完成,然后检索其结果。
Vget(long timeout, TimeUnit unit)如有必要,最多等待为使计算完成所给定的时间之后,检索其结果(如果结果可用)。
booleanisCancelled()如果在任务正常完成前将其取消,则返回 true。
booleanisDone()如果任务已完成,则返回 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 voidafterExecute(Runnable r, Throwable t)基于完成执行给定 Runnable 所调用的方法。
booleanawaitTermination(long timeout, TimeUnit unit)请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
protected voidbeforeExecute(Thread t, Runnable r)在执行给定线程中的给定 Runnable 之前调用的方法。
voidexecute(Runnable command)在将来某个时间执行给定任务。
protected voidfinalize()当不再引用此执行程序时,调用 shutdown。
intgetActiveCount()返回主动执行任务的近似线程数。
intgetCompletedTaskCount()返回已完成执行的近似任务总数。
longgetCorePoolSize()返回核心线程数。
longgetKeepAliveTime(TimeUnit unit)返回线程保持活动的时间,该时间就是超过核心池大小的线程可以在终止前保持空闲的时间值。
intgetLargestPoolSize()返回曾经同时位于池中的最大线程数。
intgetMaximumPoolSize()返回允许的最大线程数。
intgetPoolSize()返回池中的当前线程数。
BlockingQueuegetQueue()返回此执行程序使用的任务队列。
RejectedExecutionHandlergetRejectedExecutionHandler()返回用于未执行任务的当前处理程序。
longgetTaskCount()返回计划执行的近似任务总数。
ThreadFactorygetThreadFactory()返回用于创建新线程的线程工厂。
booleanisShutdown()如果此执行程序已关闭,则返回 true。
booleanisTerminated()如果关闭后所有任务都已完成,则返回 true。
booleanisTerminating()如果此执行程序处于在 shutdown 或 shutdownNow 之后正在终止但尚未完全终止的过程中,则返回 true。
intprestartAllCoreThreads()启动所有核心线程,使其处于等待工作的空闲状态。
booleanprestartCoreThread()启动核心线程,使其处于等待工作的空闲状态。
voidpurge()试图从工作队列移除所有已取消的 Future 任务。
booleanremove(Runnable task)从执行程序的内部队列中移除此任务(如果出现),这样如果尚未开始,则其不再运行。
voidsetCorePoolSize(int corePoolSize)设置核心线程数。
voidsetKeepAliveTime(long time, TimeUnit unit)设置线程在终止前可以保持空闲的时间限制。
voidsetMaximumPoolSize(int maximumPoolSize)设置允许的最大线程数。
voidsetRejectedExecutionHandler(RejectedExecutionHandler handler)设置用于未执行任务的新处理程序。
voidsetThreadFactory(ThreadFactory threadFactory)设置用于创建新线程的线程工厂。
voidshutdown()按过去执行已提交任务的顺序发起一个有序的关闭,但是不接受新任务。
ListshutdownNow()尝试停止所有的活动执行任务、暂停等待任务的处理,并返回等待执行的任务列表。
protected voidterminated()当 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
		
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值