博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
定制并发类(三)实现一个基于优先级的Executor类
阅读量:5935 次
发布时间:2019-06-19

本文共 3149 字,大约阅读时间需要 10 分钟。

声明:本文是《 》的第七章,作者: Javier Fernández González     译者:许巧辉

实现一个基于优先级的Executor类

在Java并发API的第一个版本中,你必须创建和运行应用程序中的所有线程。在Java版本5中,随着执行者框架(Executor framework)的出现,对于并发任务的执行,一个新的机制被引进。

使用执行者框架(Executor framework),你只要实现你的任务并把它们提交给执行者。这个执行者负责执行你的任务的线程的创建和执行。

在内部,一个执行者使用一个阻塞队列来存储待处理任务。以任务到达执行者的顺序来存储。一个可能的替代就是使用一个优先级列队来存储新的任务。这样,如果一个高优先级的新任务到达执行者,它将比其他已经在等待一个线程来执行它们,且低优先级的任务先执行。

在这个指南中,你将学习如何实现一个执行者,它将使用优先级队列来存储你提交执行的任务。

准备工作

这个指南的例子使用Eclipse IDE实现。如果你使用Eclipse或其他IDE,如NetBeans,打开它并创建一个新的Java项目。

如何做…

按以下步骤来实现的这个例子:

1.创建一个MyPriorityTask类,它实现Runnable接口和参数化为MyPriorityTask类的Comparable接口。

1 public class MyPriorityTask implements Runnable,
2 Comparable<MyPriorityTask> {

2.声明一个私有的、int类型的属性priority。

1 private int priority;

3.声明一个私有的、String类型的属性name。

1 private String name;

4.实现这个类的构造器,并初始化它的属性。

1 public MyPriorityTask(String name, int priority) {
2 this.name=name;
3 this.priority=priority;
4 }

5.实现一个方法来返回priority属性的值。

1 public int getPriority(){
2 return priority;
3 }

6.实现声明在Comparable接口中的compareTo()方法。它接收一个MyPriorityTask对象作为参数,比较这两个对象(当前对象和参数对象)的优先级。让优先级高的任务先于优先级低的任务执行。

01 @Override
02 public int compareTo(MyPriorityTask o) {
03 if (this.getPriority() < o.getPriority()) {
04 return 1;
05 }
06 if (this.getPriority() > o.getPriority()) {
07 return -1;
08 }
09 return 0;
10 }

7.实现run()方法。令当前线程睡眠2秒。

01 @Override
02 public void run() {
03 System.out.printf("MyPriorityTask: %s Priority :
04 %d\n",name,priority);
05 try {
06 TimeUnit.SECONDS.sleep(2);
07 } catch (InterruptedException e) {
08 e.printStackTrace();
09 }
10 }

8.实现这个例子的主类,通过创建Main类,并实现main()方法。

1 public class Main {
2 public static void main(String[] args) {

9.创建一个ThreadPoolExecutor对象,名为executor。使用参数化为Runnable接口的PriorityBlockingQueue作为执行者用来存储待处理任务的队列。

1 ThreadPoolExecutor executor=new ThreadPoolExecutor(2,2,1,TimeU
2 nit.SECONDS,new PriorityBlockingQueue<Runnable>());

10.提交4个使用循环计数器作为优先级的任务给执行者。使用execute()方法提交这些任务给执行者。

1 for (int i=0; i<4; i++){
2 MyPriorityTask task=new MyPriorityTask ("Task "+i,i);
3 executor.execute(task);
4 }

11.令当前线程睡眠1秒。

1 try {
2 TimeUnit.SECONDS.sleep(1);
3 } catch (InterruptedException e) {
4 e.printStackTrace();
5 }

12.提交4个额外的,使用循环计数器作为优先级的任务给执行者。使用execute()方法提交这些任务给执行者。

1 for (int i=4; i<8; i++) {
2 MyPriorityTask task=new MyPriorityTask ("Task "+i,i);
3 executor.execute(task);
4 }

13.使用shutdown()方法关闭这个执行者。

1 executor.shutdown();

14.使用awaitTermination()方法等待这个执行者的结束。

1 try {
2 executor.awaitTermination(1, TimeUnit.DAYS);
3 } catch (InterruptedException e) {
4 e.printStackTrace();
5 }

15.写入一条信息表明这个程序的结束。

1 System.out.printf("Main: End of the program.\n");

它是如何工作的…

很容易将执行者转换成一个基于优先级的(执行者)。你只要传入一个参数化为Runnable接口的PriorityBlockingQueue对象作为参数。但是,使用执行者时,你应该知道存储在优先级列队中的所有对象必须实现Comparable接口。

你已经实现了MyPriorityTask类,(作为一个任务)它实现了Runnable接口和Comparable接口,它被存储在优先级队列中。这个类有一个Priority属性,用来存储任务的优先级。如果一个任务的这个属性有更高的值,它将被更早的执行。compareTo()方法决定任务在优先级列队中的顺序。在Main类,你提交8个不同优先级的任务给执行者。你提交给执行者的第一个任务将第一个被执行。由于执行者闲置的,正在等待任务被执行,当第一个任务到达执行者时,执行者立即执行它们。你已经创建有2个执行线程的执行者,所以,前两个任务将第一个被执行。然后,剩下的任务将按它们的优先级来执行。

以下截图显示了示例的一次执行:

不止这些…

你可以使用任何实现BlockingQueue接口(的队列)来配置执行者。DelayQueue是一个有趣的实现。这个类被用来存储延迟激活(delayed activation)的元素。它提供只返回活动对象的方法。你可以使用这个类来实现自己版本的ScheduledThreadPoolExecutor类。

转载地址:http://cjntx.baihongyu.com/

你可能感兴趣的文章
vue 解决循环引用组件报错的问题
查看>>
手把手教你搭APM之Skywalking搭建指南(支持Java/C#/Node.js)
查看>>
ES6中的Set数据结构
查看>>
[LeetCode] 559. Maximum Depth of N-ary Tree
查看>>
Vue学习第三天
查看>>
出场率比较高的一道多线程安全面试题
查看>>
lodash速览:集合方法(二)
查看>>
Serverless+SCF=打倒服务器,解放程序员
查看>>
Java中获取类名的3种方法!
查看>>
React Native 屏幕适配(炒鸡简单的方法)
查看>>
Mac High Sierra版本中“已损毁,打不开。您应该将它移到废纸篓”问题的解决办法...
查看>>
关于 nginx 前端知道这些就够了
查看>>
Golang Gin实践 连载十二 优化配置结构及实现图片上传
查看>>
jCasbin:支持MAC、RBAC、ABAC多种模型的Java权限管理框架
查看>>
多线程基础必要知识点!看了学习多线程事半功倍
查看>>
laravel 内容理解和摘要
查看>>
订阅号页面偷取微信用户信息(unionId),-_-
查看>>
PHP SPL 笔记
查看>>
HTML、CSS笔记
查看>>
让前端攻城师独立于后端进行开发: Mock.js
查看>>