Java内置线程池ExecutorService介绍及商品秒杀案例

第一、ExecutorService接口是java内置的线程池接口,通过学习接口中的方法,可以快速的掌握java内置线程池的基本使用
常用方法:

void shutdown() 启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
List shutdownNow() 停止所有正在执行的任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
Future submit(Callable task) 执行带返回值的任务,返回一个Future对象。
Future<?> submit(Runnable task) 执行 Runnable 任务,并返回一个表示该任务的 Future。
Future submit(Runnable task, T result) 执行 Runnable 任务,并返回一个表示该任务的 Future。
第二、获取ExecutorService可以利用JDK中的Executors 类中的静态方法,常用获取方式如下:
static ExecutorService newCachedThreadPool() 创建一个默认的线程池对象,里面的线程可重用,且在第一次使用时才创建
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
线程池中的所有线程都使用ThreadFactory来创建,这样的线程无需手动启动,自动执行;
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory)
创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建。
static ExecutorService newSingleThreadExecutor()
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
创建一个使用单个 worker 线程的 Executor,且线程池中的所有线程都使用ThreadFactory来创建。
第三、ScheduledExecutorService是ExecutorService的子接口,具备了延迟运行或定期执行任务的能力,
常用获取方式如下:
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个可重用固定线程数的线程池且允许延迟运行或定期执行任务;
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建,且允许延迟运行或定期执行任务;
static ScheduledExecutorService newSingleThreadScheduledExecutor()
创建一个单线程执行程序,它允许在给定延迟后运行命令或者定期地执行。
static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory)
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行
第四、Java内置线程池-异步计算结果(Future)
我们刚刚在学习java内置线程池使用时,没有考虑线程计算的结果,但开发中,我们有时需要利用线程进行一些计算,然后获取这些计算的结果,而java中的Future接口就是专门用于描述异步计算结果的,我们可以通过Future 对象获取线程计算的结果;
Future 的常用方法如下:
boolean cancel(boolean mayInterruptIfRunning)
试图取消对此任务的执行。
V get()
如有必要,等待计算完成,然后获取其结果。
V get(long timeout, TimeUnit unit)
如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。
boolean isCancelled()
如果在任务正常完成前将其取消,则返回 true。
boolean isDone()
如果任务已完成,则返回 true。
第五、综合案例-秒杀商品
案例介绍:假如某网上商城推出活动,新上架5部新手机免费送客户体验,要求所有参与活动的人员在规定的时间同时参与秒杀挣抢,假如有10人同时参与了该活动,请使用线程池模拟这个场景,保证前5人秒杀成功,后5人秒杀失败;
要求:1:使用线程池创建线程;2:解决线程安全问题
思路提示:
1:既然商品总数量是5个,那么我们可以在创建线程池的时候初始化线程数是5个及以下,设计线程池最大数量为5个;
2:当某个线程执行完任务之后,可以让其他秒杀的人继续使用该线程参与秒杀;
3:使用synchronized控制线程安全,防止出现错误数据;
任务类

/**
 * 任务类(商品数量、客户名称、送手机行为)
 * @author shixiangcheng
 * 2022-05-14
 */
public class MyTask implements Runnable{
	//设计一个变量,标识商品数量
	private static int id=5;
	//标识客户名称和数量
	private String userName;
	public MyTask(String userName) {
		this.userName=userName;
	}
	@Override
	public void run() {
		String name=Thread.currentThread().getName();
		System.out.println(userName+"正在使用:"+name+"参与秒杀任务!");
		try {
			Thread.sleep(200);//休眠200毫秒
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		synchronized(MyTask.class) {
			if(id>0) {
				System.out.println(userName+"正在使用:"+name+"秒杀"+id--+"号商品成功啦!");
			}else {
				System.out.println(userName+"正在使用:"+name+"秒杀失败啦!");
			}
		}
	}
}

主程序类

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * 主程序类测试任务类
 * @author shixiangcheng
 * 2022-05-14
 */
public class MyTest {
	public static void main(String[] args) {
		//1.创建一个线程池对象
		ThreadPoolExecutor executor=new ThreadPoolExecutor(3,5,1,TimeUnit.MINUTES,new LinkedBlockingQueue<>(15));
		//2.循环创建任务对象
		for(int i=1;i<=10;i++) {
			MyTask myTask=new MyTask("客户"+i);
			executor.submit(myTask);
		}
		//3.关闭线程池
		executor.shutdown();
	}
}

执行结果

客户2正在使用:pool-1-thread-2参与秒杀任务!
客户3正在使用:pool-1-thread-3参与秒杀任务!
客户1正在使用:pool-1-thread-1参与秒杀任务!
客户2正在使用:pool-1-thread-2秒杀5号商品成功啦!
客户3正在使用:pool-1-thread-3秒杀4号商品成功啦!
客户4正在使用:pool-1-thread-2参与秒杀任务!
客户1正在使用:pool-1-thread-1秒杀3号商品成功啦!
客户5正在使用:pool-1-thread-3参与秒杀任务!
客户6正在使用:pool-1-thread-1参与秒杀任务!
客户5正在使用:pool-1-thread-3秒杀2号商品成功啦!
客户6正在使用:pool-1-thread-1秒杀1号商品成功啦!
客户8正在使用:pool-1-thread-1参与秒杀任务!
客户7正在使用:pool-1-thread-3参与秒杀任务!
客户4正在使用:pool-1-thread-2秒杀失败啦!
客户9正在使用:pool-1-thread-2参与秒杀任务!
客户8正在使用:pool-1-thread-1秒杀失败啦!
客户10正在使用:pool-1-thread-1参与秒杀任务!
客户9正在使用:pool-1-thread-2秒杀失败啦!
客户7正在使用:pool-1-thread-3秒杀失败啦!
客户10正在使用:pool-1-thread-1秒杀失败啦!

第六、线程池的使用步骤可以归纳总结为五步
1.利用Executors工厂类的静态方法创建线程池对象
2.编写Runnable或Callable实现类的实例对象
3.利用ExecutorService的submit方法或ScheduledExecutorService的schedule方法提交并执行线程任务
4.如果有执行结果,则处理异步执行结果(Future)
5.调用shutdown()方法关闭线程池
第七、ExecutorService

private static ExecutorService executorService;
static {//初始化线程池
    if (executorService == null) {
    	executorService = Executors.newFixedThreadPool(20);
    }
}
//异步处理
executorService.execute(new Runnable() {
    @Override
    public void run() {
        try {
        } catch (Exception e) {
        }
    }
});

欢迎大家积极留言交流学习心得,点赞的人最美丽!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以使用配置类来配置Executor线程池。其中,常用的实现类是`ExecutorService`和`ThreadPoolTaskExecutor`。 首先,需要创建一个配置类,可以命名为`ThreadPoolConfig`或者其他你喜欢的名称。在这个类中,你需要使用`@Configuration`注解来标识它是一个配置类,并且使用`@EnableAsync`注解来启用异步执行。 接下来,你需要定义一个`ExecutorService`或`ThreadPoolTaskExecutor` Bean,并使用`@Bean`注解将其标识为一个Bean。你可以根据项目的需求来选择使用哪个实现类。 如果选择使用`ExecutorService`,可以按照以下方式配置: ```java @Configuration @EnableAsync public class ThreadPoolConfig { @Bean public ExecutorService executorService() { return Executors.newFixedThreadPool(10); // 配置线程池的大小 } } ``` 如果选择使用`ThreadPoolTaskExecutor`,可以按照以下方式配置: ```java @Configuration @EnableAsync public class ThreadPoolConfig { @Bean public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); // 设置核心线程数 executor.setMaxPoolSize(20); // 设置最大线程数 executor.setQueueCapacity(30); // 设置队列容量 executor.setThreadNamePrefix("my-executor-"); // 设置线程名称前缀 executor.initialize(); // 初始化 return executor; } } ``` 在上述配置中,你可以根据实际需求来设置线程池的大小、队列容量等参数。通过这种方式,你就可以在应用程序中注入`ExecutorService`或`ThreadPoolTaskExecutor`,并使用它来执行异步任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值