Day25线程池

什么是线程池

本质就是将任务放到阻塞队列里,然后线程池如果有空闲线程是就执行它

线程池就是可以复用线程的技术

JDK5起提供了代表线程池的接口:ExecutorService

线程池的好处

1.重用已经存在的线程,降低系统资源消耗。
2.减少线程创建和销毁造成的消耗
3.管控线程的并发。
4.提供一些更加强大的功能

如何得到线程池对象

方法一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程对象

方法二:使用Executors(线程池工具类)调用方法返回不同特点的线程池对象

ThreadPoolExecutor构造器线程池的核心参数

  • corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。不能小于0
  • maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。 最大数量>=核心线程数量
  • keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。不能小于0
  • unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。时间单位
  • workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。不能为null
  • threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。不能为null
  • handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。不能为null

CorePoolSize:核心线程数,核心线程会一直存活。

maximumPoolSize:最大线程数,决定线程池最多可以创建多少线程。

keepAliveTime:空闲时间,当线程闲置超过空闲时间时就会被销毁。

unit:空闲时间的单位。

workQueue:缓冲队列

  • ArrayBlockingQueue:有界队列,有最大容量闲置。

  • LinkedBlockingQueue:*队列,不限制容量。

  • SynchronousQueue:同步队列,内部没有缓冲区。

threadFactory:设置线程池工厂方法,用来创建新的线程方法,可以对线程的属性进行定制,例如线程的group,线程名等,一般使用默认的工厂类即可。

handler:线程池满时的拒绝策略,

  • Abort:线程池满后,提交新任务时,会抛出异常,默认拒绝策略。

  • Discard:线程池满后,提交新任务时,对任务进行丢弃。

  • CallerRuns:线程池满后,提交新任务时,会直接找主线程执行提交的任务。

  • DiscardOldest:线程池满后,提交新任务时,会丢弃最早提交的任务。

volatile内存可见

线程池处理Runnable任务

7个核心参数创建线程池:3核心线程 5最大线程数量 8空闲线程的存活时间 TimeUnit.MILLISECONDS毫秒单位 new ArrayBlockingQueue<>(5)数组阻塞队列 Executors.defaultThreadFactory() 线程工程 new ThreadPoolExecutor.AbortPolicy()任务拒绝策略

ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolic3.y());
package com.lanou.pool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
//自定义线程池对象 测试其特性
public class MyThread {
	
	public static void main(String[] args) {
		//1.创建线程池对象
		/*
		 *  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
		 */
		ExecutorService pool = new ThreadPoolExecutor(3, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),
				new ThreadPoolExecutor.AbortPolicy());
		//2.给任务线程池处理
		Runnable target = new MyRunnable();
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		pool.execute(target);
		//创建临时线程
		pool.execute(target);
		pool.execute(target);
		//拒绝策略 不创建
		pool.execute(target);
		//关闭线程池()开发中不会使用
		pool.shutdown();//立即关闭及时任务没有完成,丢失任务
	}

}
package com.lanou.pool;

public class MyRunnable implements Runnable{
	@Override
	public void run() {
		for(int i = 0; i<5; i++) {
			System.out.println(Thread.currentThread().getName()+"输出了"+i);
			
		}
		// TODO Auto-generated method stub
		try {
			System.out.println(Thread.currentThread().getName()+"本任务与线程绑定了,线程睡眠");
			Thread.sleep(100000);
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

线程池处理Callable任务

package com.lanou.demo;
 
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
 
/*
 *  实现线程程序的第三个方式,实现Callable接口方式
 *  实现步骤
 *    工厂类 Executors静态方法newFixedThreadPool方法,创建线程池对象
 *    线程池对象ExecutorService接口实现类,调用方法submit提交线程任务
 *    submit(Callable c)
 */
public class Demo {
	public static void main(String[] args)throws Exception {
		ExecutorService es = Executors.newFixedThreadPool(2);
		//submit方法提交线程任务,返回 Future接口实现类的对象
		Future<String> result = es.submit(new ThreadPoolCallable()); // 返回的Future表示线程执行的结果。 submit可以传Runnable接口,也可以传Callable接口
		String s = result.get();  // 从Future中获取结果。
		System.out.println(s);
		
		es.shutdown();  // 关闭线程池。 (不经常用)
	}
}

package com.lanou.demo;
/*
 * Callable 接口的实现类,作为线程提交任务出现
 * 使用方法返回值
 */
 
import java.util.concurrent.Callable;
 
public class ThreadPoolCallable implements Callable<String>{  // 实现Callable接口
	public String call(){  // 重写call方法。 可以有返回值
		return "abc";  // 可以有返回值。 线程池中用Future接口实现类接收结果。
	}
}

Callable接口实现多线程(未使用线程池):

CallableTest.java:

package com.lanou.juc;
 
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
 
class MyCall implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
		System.out.println(Thread.currentThread().getName()+" Come in call");
		//睡5秒
		TimeUnit.SECONDS.sleep(5);
		//返回200的状态码
		return 200;
	}
}
 
 
public class CallableTest {
 
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//创建MyThread对象
		MyCall myCall = new MyCall();
		//创建未来任务对象
		FutureTask<Integer> futureTask = new FutureTask<>(myCall);  // FutureTask实现了Future接口和Runnable接口,是Callable与Runnable之间的桥梁
		//创建处理未来任务的线程(多线程)
		new Thread(futureTask, "未来任务名").start();
		System.out.println(Thread.currentThread().getName()+"主线程继续");
		//获取未来任务的结果(Callable的返回值)
		Integer result = futureTask.get();   // get()方法会阻塞当前线程
		System.out.println(result);
		Integer result2 = futureTask.get();   // 多次调用get()并不会重新执行耗时的未来任务
		System.out.println(result2);
	}
 
}

Executors得到线程池对象的常用方法

Day25线程池

注意:Executors的底层也是基于线程池的实现类ThreadPoolExcutor创建线程池对象的.

Day25线程池

package com.lanou.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPool {
	public static void main(String[] args) {
		//1.创建固定线程数据的线程池
		/*
		 * public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,  
                                      new LinkedBlockingQueue<Runnable>());/
		 */
		ExecutorService pool = Executors.newFixedThreadPool(3);//固定几个线程
		pool.execute(new MyRunnable());
		pool.execute(new MyRunnable());
		pool.execute(new MyRunnable());
		pool.execute(new MyRunnable());//已经没有多余线程
	}

}
package com.lanou.pool;

public class MyRunnable implements Runnable{
	@Override
	public void run() {
		for(int i = 0; i<5; i++) {
			System.out.println(Thread.currentThread().getName()+"输出了"+i);
			
		}
		// TODO Auto-generated method stub
		try {
			System.out.println(Thread.currentThread().getName()+"本任务与线程绑定了,线程睡眠");
			Thread.sleep(100000);
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

Executors使用可能存在陷阱

Day25线程池

阿里巴巴开发手册不允许使用

上一篇:线程理论详解 | 守护线程 | 线程互斥锁


下一篇:为什么基于PR比基于Rating效果好?