互联网复习五(线程池)
// 查看硬件的核数Runtime.getRuntime().availableProcessors();
为什么用线程池,优势?
作用:控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
优势:线程复用、控制最大并发数、管理线程。
线程调用4种方式:
1、继承Thread对象
2、实现Runnable接口
new Thread(() -> {}, "Thread-1").start();
3、实现Callable<V>接口
/*** 线程操作*/class CallableDemo implements Callable<Cake>{@Overridepublic Cake call() throws Exception {// 业务处理Cake cake = new Cake("白雪公主", "90元");return cake;}public void test() throws ExecutionException, InterruptedException {FutureTask<Cake> futureTask = new FutureTask<>(new CallableDemo());new Thread(futureTask, "Thread-1").start();//相同的事情,不会做重复的事情//new Thread(futureTask, "Thread-2").start();while ( !futureTask.isDone() ){// 自循等待线程完成操作}// 获取线程完成后返回结果值Cake cake = futureTask.get();}}
4、获取线程,通过线程池获取线程
Excutors.newScheduledThreadPool();
// 使用目前机器上可用的处理器作为它的并发级别
Excutors.newWorkStealingPool(int);
// 一池固定线程
Excutors.newFixedThreadPool(int);
// 一池一线程
Excutors.newSingleThreadExcutor();
// 一池多线程
Excutors.newCachedThreadPool();
线程池底层实现:
1、ThreadPoolExcutor类使用
2、阻塞队列
7大参数介绍:
1、corePoolSize 线程池中常驻核心线程数
2、maxnumPoolSize 线程池能够容纳同时执行最大线程数,此值必须大于等于1
3、keepAliveTime 多余的空闲线程的存活时间;当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime值时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止
4、unit keepAliveTime单位
5、workQueue 任务队列,被提交但尚未被执行的任务
6、threadFactory 表示生成线程池中工作线程的线程工厂,用于创建线程一般默认
7、handler 拒绝策略,表示当队列满了并且工作线程大于等于线程池的最大线程数(maxnumPoolSize)时如何拒绝请求执行的runnable的策略
业务理解:
1、在创建了线程池后,等待提交过来的任务请求
2、当调用execute()方法添加一个请求任务时,线程池会做如下判断:
2.4、如果队列满了且正在远行的线程数量大于maxnumPoolSize,那么线程池会启动饱和拒绝策略来执行
3、当一个线程完成任务时,它会从队列取下一个任务来执行
4、当一个线程无事可做超过一定时间(keepAliveTime)时,线程池会判断
工作中是如何使用线程池的?是否自定义过线程池使用?
1、数据库线程池
2、redis线程池
自己定义代码:
ExecutorService threadPool =new ThreadPoolExecutor(3, // corePoolSize 核心线程数5, // maxnumPoolSize 同执行最大线程数1L, // keepAliveTime 闲置线程存活时间TimeUnit.SECONDS, // keepAliveTime 单位new LinkedBlockingDeque<>(3), // 阻塞队列 等待区Executors.defaultThreadFactory(), // 创建线程工厂new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略(抛异常)for (int i = 0; i < 10; i++) {threadPool.execute(() -> {System.out.println(Thread.currentThread().getName() + "\t 办理业务");});}
运行结果:
pool-1-thread-1 办理业务pool-1-thread-1 办理业务pool-1-thread-1 办理业务Exception in thread "main" pool-1-thread-1 办理业务pool-1-thread-2 办理业务java.util.concurrent.RejectedExecutionException: Task com.xiai.mini.TestMain$$Lambda$1/540585569@78c03f1f rejected from java.util.concurrent.ThreadPoolExecutor@5383967b[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 5]at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)at com.xiai.mini.TestMain.main(TestMain.java:40)pool-1-thread-3 办理业务pool-1-thread-4 办理业务pool-1-thread-5 办理业务
合理配置线程池是任何考虑的?
CPU密集型:CPU核数+1
IO密集型:
死锁编码及定位分析?
指两个或者两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若外力干涉那它们都将无法推进下去
主要原因:系统资源不足、进程运行推进的不合适、资源分配不当
实现代码:
class DeadThreadDemo implements Runnable{private String lockOne;private String lockTwo;public DeadThreadDemo(String lockOne, String lockTwo) {this.lockOne = lockOne;this.lockTwo = lockTwo;}@Overridepublic void run() {synchronized (lockOne){System.out.println(Thread.currentThread().getName() + "\t 获取到锁:" + lockOne + ", 但尝试获取" + lockTwo);try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }synchronized (lockTwo){System.out.println(Thread.currentThread().getName() + "\t 获取到锁:" + lockTwo + ", 但尝试获取" + lockOne);}}}public static void main(String[] args){String lockOne = "lock-One";String lockTwo = "lock-Two";new Thread(new DeadThreadDemo(lockOne, lockTwo)).start();new Thread(new DeadThreadDemo(lockTwo, lockOne)).start();}}
运行结果:
解决:
